使用 InternLM 构建个人 AI 助手:Prompt、RAG、Agent 与 XTuner 微调
这篇文章把四次相对独立的实践整理成一条完整路线:先用结构化 Prompt 约束模型,再用 RAG 补充外部知识,随后通过 Agent 连接工具,最后用微调固化稳定的行为与风格。
这四种技术并不是互相替代的关系。它们分别解决“如何表达任务”“如何获得知识”“如何执行动作”和“如何形成长期能力”四类问题。
能力路线
| 层次 | 技术 | 主要解决的问题 | 适合优先使用的场景 |
|---|---|---|---|
| 任务表达 | LangGPT / Prompt | 输出不稳定、格式不统一、推理步骤不清晰 | 需求可以通过文字明确描述 |
| 外部知识 | RAG / LlamaIndex | 模型不知道私有资料或最新内容 | 文档问答、知识库检索 |
| 工具执行 | Lagent | 模型只能回答,不能搜索、计算或调用服务 | 需要调用工具完成多步任务 |
| 行为固化 | XTuner | 仅靠提示词难以长期保持风格或能力 | 有高质量训练数据且需求稳定 |
实际开发时,通常应该按表格从上到下逐层增加复杂度,而不是一开始就进行微调。
LangGPT:先让模型准确理解任务
结构化提示词是成本最低、反馈最快的一层。下面保留当时针对浮点数比较问题的实践记录,并包含模型服务和 tmux 的基础操作。
前言
在日常使用大模型时,我发现它经常在数字比对这类基础问题上出错,并且输出结果很不严谨。为了解决这个问题,我尝试使用Prompt Engineering, 并在网上找到了一个开源的「结构化提示词框架」— LangGPT,以下是我的使用过程记录。
实现步骤
step0:前期准备
- 创建虚拟环境->激活虚拟环境->安装必要包文件
- 创建项目路径->进入项目
- 安装必要软件,如tmux
step1:模型部署 模型下载->部署模型为OpenAI server->图形化界面调用
step3:langgpt结构化提示词编写 偷懒大法:GPTS有LangGPT提示词专家,用大模型生成即可
tmux使用
tmux可以在终端中创建终端,将进程维持在后台。
所以当我们下载模型,使用tmux在后台下载时,即便我们断开ssh连接,下载也不会中断。
step1:部署模型为OpenAI server
tmux常见命令
1.创建窗口命令:
PS:t表示target(目标),用于指定会话、窗口或面板的名称
tmux new -t <session_name>PS:创建完成后,运行下面的命令进入新的命令窗口(首次创建自动进入,之后需要连接):
其中a 是 attach 的简写
tmux a -t <session_name>2.查看当前 tmux 会话:
tmux ls3.连接到特定的 tmux 会话:
tmux attach -t <session_name>将 <session_name> 替换为你要连接的会话的实际名称或编号。
4.杀死整个 tmux 会话:
tmux kill-session -t <session_name>5.退出tmux:
Ctrl+B进入tmux的控制模式,然后按d退出窗口连接
模型部署
进入命令窗口后,需要在新窗口中再次激活环境,命令参考0.1节。然后,使用LMDeploy进行部署,参考如下命令:
使用LMDeploy进行部署,参考如下命令:
CUDA_VISIBLE_DEVICES=0 lmdeploy serve api_server /share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b --server-port 23333 --api-keys internlm2更多设置参考:https://lmdeploy.readthedocs.io/en/latest/index.html
部署成功后,可以利用如下脚本调用部署的InternLM2-chat-1_8b模型并测试是否部署成功。
from openai import OpenAI
client = OpenAI( api_key = "internlm2", base_url = "http://0.0.0.0:23333/v1")
response = client.chat.completions.create( model=client.models.list().data[0].id, messages=[ {"role": "system", "content": "请介绍一下你自己"} ])
print(response.choices[0].message.content)服务启动完成后,可以按Ctrl+B进入tmux的控制模式,然后按D退出窗口连接,更多操作参考。
作业:
基础任务 (完成此任务即完成闯关):
-
背景问题:近期相关研究发现,LLM在对比浮点数字时表现不佳,经验证,internlm2-chat-1.8b (internlm2-chat-7b)也存在这一问题,例如认为
13.8<13.11。 -
任务要求:利用LangGPT优化提示词,使LLM输出正确结果。完成一次并提交截图即可
使用GPTS中LangGPT提示词专家,配合我们的需求生成LangGPT结构化提示词
生成结果如下:
# Role: 数学助手
## Profile- author: LangGPT- version: 1.0- language: 中文- description: 一个能够进行基本数学加减法运算,并能够比较两个数字大小的助手。
## Skills1. 能够进行基本的数学加法和减法运算。2. 能够比较两个数字的大小,并给出相应的判断。3. 能够理解用户输入的简单数学表达式或问题描述。
## Rules1. 用户输入可以是任意两个数字或一个包含加法、减法的表达式。2. 当输入两个数字时,助手应比较它们的大小,并返回结果。3. 当输入一个加法或减法表达式时,助手应计算出结果并返回。4. 如果用户输入有误或不符合数学表达式规则,助手应给出提示并要求重新输入。
## Workflows1. 接收用户输入的数字或数学表达式。2. 判断输入的类型(两个数字或数学表达式)。3. 如果是两个数字,执行大小比较,并返回结果。4. 如果是数学表达式,进行加法或减法计算,返回结果。5. 如果输入不符合预期格式,返回错误提示,要求用户重新输入。
## Init1. 向用户介绍助手的功能和使用方法。2. 提示用户可以输入两个数字进行比较,或输入一个加法、减法表达式进行计算。加入系统提示词前:
PS:估计InternLM2-chat-1_8b版本太久远了,所以回答不出来🤔

加入系统提示词后:
PS:效果明显变好了😋

Reference:
1.LangGPT社区:LangGPT结构化提示词 - 飞书云文档 2.浦语开源文档书生浦语-浦语提示词工程实践 3.文档:系统论述文章: 构建高性能 Prompt 之路——结构化 Prompt
RAG:给助手接入自己的知识库
当问题来自私有文档或模型训练后的新知识时,仅修改 Prompt 不够。RAG 会先检索相关资料,再把检索结果交给模型生成答案。
一、前置知识
- 给模型注入新知识的方式:
- 内部方式:更新模型的权重,但训练代价较大。
- 外部方式:给模型注入额外的上下文或外部信息,不改变其权重。
- RAG 工作原理:
- 将问题编码成向量,在向量数据库中找到最相关的文档块(top-k chunks)。
- 将知识源分割成小块,编码成向量并存储在向量数据库中。
- 将检索到的文档块与原始问题一起作为提示输入到 LLM 中,生成最终的回答。
- RAG 效果比对:
- 由于
xtuner是较新的框架,InternLM2-Chat-1.8B训练数据库中未收录相关信息,使用 RAG 前问答均未给出准确答案,使用后能获得想要的答案。
- 由于
二、环境、模型准备
(一)配置基础环境
-
在
Intern Studio服务器上部署LlamaIndex:- 打开
Intern Studio界面,点击创建开发机配置开发机系统。 - 填写
开发机名称后,点击选择镜像使用Cuda11.7-conda镜像,在资源配置中选择30% A100 * 1的选项,立即创建开发机器。 - 进入开发机后,创建新的
conda环境,命名为llamaindex,运行以下命令:
Terminal window conda create -n llamaindex python=3.10conda env listconda activate llamaindexconda install pytorch**2.0.1 torchvision**0.15.2 torchaudio==2.0.2 pytorch-cuda=11.7 -c pytorch -c nvidiapip install einops**0.7.0 protobuf**5.26.1- 环境激活后,命令行左边会显示当前环境名称。
- 打开
(二)安装 LlamaIndex
-
安装
LlamaIndex和相关的包:Terminal window conda activate llamaindexpip install llama-index**0.10.38 llama-index-llms-huggingface**0.2.0 "transformers[torch]**4.41.1" "huggingface_hub[inference]**0.23.1" huggingface_hub**0.23.1 sentence-transformers**2.7.0 sentencepiece==0.2.0
(三)下载 Sentence Transformer 词嵌入模型
-
新建一个
python文件,贴入以下代码:import os# 设置环境变量os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'# 下载模型os.system('huggingface-cli download --resume-download sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/model/sentence-transformer') -
在
/root/llamaindex_demo目录下执行该脚本自动开始下载。
(四)下载 NLTK 相关资源
-
使用以下命令下载
nltk资源并解压到服务器上:Terminal window cd /rootgit clone https://gitee.com/yzy0612/nltk_data.git --branch gh-pagescd nltk_datamv packages/* ./cd tokenizersunzip punkt.zipcd ../taggersunzip averaged_perceptron_tagger.zip
三、LlamaIndex HuggingFaceLLM
-
运行以下指令,把
InternLM2 1.8B软连接出来:Terminal window cd ~/modelln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b/ ./ -
新建一个
python文件,贴入以下代码:from llama_index.llms.huggingface import HuggingFaceLLMfrom llama_index.core.llms import ChatMessagellm = HuggingFaceLLM(model_name="/root/model/internlm2-chat-1_8b",tokenizer_name="/root/model/internlm2-chat-1_8b",model_kwargs={"trust_remote_code": True},tokenizer_kwargs={"trust_remote_code": True})rsp = llm.chat(messages=[ChatMessage(content="xtuner 是什么?")])print(rsp) -
运行以下命令:
Terminal window conda activate llamaindexcd ~/llamaindex_demo/python llamaindex_internlm.py -
结果回答效果并不好,不是想要的
xtuner。
四、LlamaIndex RAG
-
安装
LlamaIndex词嵌入向量依赖:Terminal window conda activate llamaindexpip install llama-index-embeddings-huggingface**0.2.0 llama-index-embeddings-instructor**0.1.3 -
获取知识库:
Terminal window cd ~/llamaindex_demomkdir datacd datagit clone https://github.com/InternLM/xtuner.gitmv xtuner/README_zh-CN.md ./ -
新建一个
python文件,贴入以下代码:from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settingsfrom llama_index.embeddings.huggingface import HuggingFaceEmbeddingfrom llama_index.llms.huggingface import HuggingFaceLLM# 初始化一个 HuggingFaceEmbedding 对象,用于将文本转换为向量表示embed_model = HuggingFaceEmbedding(model_name="/root/model/sentence-transformer")Settings.embed_model = embed_modelllm = HuggingFaceLLM(model_name="/root/model/internlm2-chat-1_8b",tokenizer_name="/root/model/internlm2-chat-1_8b",model_kwargs={"trust_remote_code": True},tokenizer_kwargs={"trust_remote_code": True})Settings.llm = llm# 从指定目录读取所有文档,并加载数据到内存中documents = SimpleDirectoryReader("/root/llamaindex_demo/data").load_data()index = VectorStoreIndex.from_documents(documents)query_engine = index.as_query_engine()response = query_engine.query("xtuner 是什么?")print(response) -
运行以下命令:
Terminal window conda activate llamaindexcd ~/llamaindex_demo/python llamaindex_RAG.py -
结果借助 RAG 技术后,能获得想要的答案。
五、LlamaIndex Web
-
安装依赖:
Terminal window pip install streamlit==1.36.0 -
新建一个
python文件,贴入以下代码:import streamlit as stfrom llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settingsfrom llama_index.embeddings.huggingface import HuggingFaceEmbeddingfrom llama_index.llms.huggingface import HuggingFaceLLMst.set_page_config(page_title="llama_index_demo", page_icon="🦜🔗")st.title("llama_index_demo")# 初始化模型@st.cache_resourcedef init_models():embed_model = HuggingFaceEmbedding(model_name="/root/model/sentence-transformer")Settings.embed_model = embed_modelllm = HuggingFaceLLM(model_name="/root/model/internlm2-chat-1_8b",tokenizer_name="/root/model/internlm2-chat-1_8b",model_kwargs={"trust_remote_code": True},tokenizer_kwargs={"trust_remote_code": True})Settings.llm = llmdocuments = SimpleDirectoryReader("/root/llamaindex_demo/data").load_data()index = VectorStoreIndex.from_documents(documents)query_engine = index.as_query_engine()return query_engine# 检查是否需要初始化模型if 'query_engine' not in st.session_state:st.session_state['query_engine'] = init_models()def greet2(question):response = st.session_state['query_engine'].query(question)return response# Store LLM generated responsesif "messages" not in st.session_state.keys():st.session_state.messages = [{"role": "assistant", "content": "你好,我是你的助手,有什么我可以帮助你的吗?"}]# Display or clear chat messagesfor message in st.session_state.messages:with st.chat_message(message["role"]):st.write(message["content"])def clear_chat_history():st.session_state.messages = [{"role": "assistant", "content": "你好,我是你的助手,有什么我可以帮助你的吗?"}]st.sidebar.button('Clear Chat History', on_click=clear_chat_history)# Function for generating LLaMA2 responsedef generate_llama_response(question):response = greet2(question)return response# User-provided promptif prompt := st.chat_input("What's on your mind?"):st.chat_message("user").write(prompt)with st.chat_message("assistant"):message_placeholder = st.empty()response = generate_llama_response(prompt)message_placeholder.write(response)st.session_state.messages.append({"role": "assistant", "content": response}) -
启动 Streamlit 服务:
Terminal window cd ~/llamaindex_demo/streamlit run llamaindex_streamlit.py -
打开浏览器,访问
https://localhost:XXX。
六、总结
- 本文介绍如何结合
LlamaIndex和InternLM2部署RAG,为大模型注入最新知识库,效果显著。
七、作业

RAG前

RAG后

使用Streamlit部署webui(使用RAG)

Lagent:让助手能够调用工具
RAG 解决“知道什么”,Agent 更关注“能够做什么”。这一部分记录 Lagent WebUI、模型服务、依赖问题和自定义工具的接入过程。
启动webui服务
使用lmdeploy启动一个api_server
conda activate agent_camp3lmdeploy serve api_server /share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat --model-name internlm2_5-7b-chat
另开一个终端,使用stremlit启动agent_web应用
cd /root/agent_camp3/lagentconda activate agent_camp3streamlit run examples/internlm2_agent_web_demo.py
本地powershell建立ssh连接,进行端口映射

Q&A
遇到的问题:
ModuleNotFoundError: No module named 'griffe.enumerations解决方法:
Due to griffe's recent 1.x release, the `griffe.enumerations` module has been removed, resulting in a break change, which can be resolved by`pip install griffe==0.48`.修改模型名称以及模型IP地址
启动streamlit的web应用如下:

修改红框内的内容

终端的反馈:
PS:很是可惜,没有找到我想要的内容[1706.03762] Attention Is All You Need (arxiv.org)

自定义工具

进入lagent_web_demo的py文件中
添加&修改代码:
from lagent.actions import ActionExecutor, ArxivSearch, IPythonInterpreter+ from lagent.actions.magicmaker import MagicMakerfrom lagent.agents.internlm2_agent import INTERPRETER_CN, META_CN, PLUGIN_CN, Internlm2Agent, Internlm2Protocol
... action_list = [ ArxivSearch(),+ MagicMaker(), ]
重新启动agent_web服务
使用MagicMaker工具绘画
Prompt:帮我画一个微笑的女孩,穿着校服在学校的走廊上,阳光照耀在她身上

可以看到对于用户输入的提示词,有自动进行填充完善


XTuner:把稳定需求固化到模型中
微调适合处理长期、重复且有训练样本支持的能力或风格。它不应替代知识库和工具系统;知识经常变化时优先使用 RAG,需要执行动作时仍要使用 Agent。原始记录主要保存了任务要求与结果截图,因此这里不补写未经验证的训练参数。
任务内容

完成任务截图

四种方案如何组合
一个实用的个人助手可以采用这样的工作流:用户输入先经过结构化 Prompt 整理;系统判断是否需要检索本地知识库;如果任务要求搜索、绘图或运行代码,再交给 Agent 调用工具;模型本身则通过少量高质量微调数据保持稳定的人设和表达习惯。
实践建议
- 先用 Prompt 做最小可行版本,确认任务边界。
- 知识变化频繁时使用 RAG,不要反复微调事实数据。
- 工具权限应尽量最小化,并为调用结果增加校验。
- 只有当需求稳定、样本可靠、收益明确时再进行微调。
- 用固定测试集分别验证准确率、引用质量、工具成功率和风格一致性。
从 Prompt 到 RAG、Agent、微调,本质上是在逐步扩展助手的可控性、知识范围、行动能力和个性化程度。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!