从零搭建一个中医养生 Agent:LangChain ReAct + FastAPI 实战
本文记录了我为“小甘草”中医养生助手构建 AI Agent 的核心过程,包括工具函数定义、LangChain ReAct Agent 搭建、本地 Ollama 集成及 FastAPI 服务封装。使用 LangChain 官方组件,兼顾开发效率与可控性。
一、背景与目标
项目简介:小甘草是一个中医养生咨询平台,用户可以通过对话询问体质、获取食疗穴位建议。
为什么需要 Agent?需要主动调用工具(查体质、生成方案、查天气等),而非简单的问答。
- 技术选型:Python + LangChain(
create_react_agent+AgentExecutor)+ Ollama(本地模型)+ FastAPI。 - 本文目标:分享从零到可用的 Agent 服务搭建过程,包括工具函数、Agent 配置、FastAPI 封装及与 Node.js 后端的集成思路。
二、整体架构
- 前端:Vue 3
- 后端:Node.js(处理用户认证、体质问卷等,调用 Agent 服务)
- Agent 服务:Python + FastAPI + LangChain(
create_react_agent) - 模型:本地 Ollama(Qwen2-1.5B)或 DeepSeek API
- 存储:Supabase(业务数据)+ ChromaDB(向量知识库,后续)
三、阶段 0:环境准备与基础设施
3.1 创建虚拟环境与安装依赖
python -m venv venv
venv\Scripts\activate
pip install fastapi uvicorn langchain langchain-community langchain-openai python-dotenv
3.2 目录结构
agent-service/
├── agents/
├── tools/
├── models/
├── rag/
├── memory/
├── utils/
├── .env
├── requirements.txt
└── main.py
3.3 环境变量配置(.env)
DEEPSEEK_API_KEY=xxx # 或使用 Ollama
3.4 锁定依赖版本
pip freeze > requirements.txt
四、阶段 1:工具函数开发(纯 Python,不依赖 LLM)
4.1 设计原则
- 工具函数只做确定性操作(查数据库、调 API、计算),不包含 LLM 调用。
- 每个工具必须有清晰的 docstring,供 LangChain 自动提取描述。
- 返回格式统一(字符串或 JSON)。
4.2 实现示例:获取用户体质
# tools/constitution.py
from langchain.tools import tool
@tool
def get_user_constitution(user_id: str) -> str:
"""根据用户ID获取中医体质类型"""
# mock 实现,后续替换为 Supabase 查询
return "气虚质"
4.3 其他工具
generate_wellness_plan:返回 mock JSON 方案。search_tcm_knowledge:返回固定文本(后续接入 RAG)。get_weather_solar_term:调用天气 API。create_reminder:调用 Node.js 提醒接口。analyze_health_trend:查询历史体质趋势。
4.4 单元测试(未完成)
注:目前工具函数尚未编写完整的单元测试,计划在后续补充。
五、阶段 2:LangChain ReAct Agent 搭建
5.1 为什么选择 LangChain 官方 Agent?
- 避免重复造轮子,专注业务逻辑。
create_react_agent+AgentExecutor提供了稳定的 ReAct 循环实现。- 内置工具调用解析、错误处理、中间步骤记录(
verbose=True)。 - 与 LangChain 生态无缝集成(后续可轻松添加记忆、RAG 等)。
5.2 初始化 LLM(本地 Ollama)
from langchain_ollama import ChatOllama
llm = ChatOllama(
model="qwen2:1.5b",
temperature=0.7,
base_url="http://localhost:11434"
)
如果使用 DeepSeek API,替换为
ChatOpenAI并配置 base_url。
5.3 绑定工具
tools = [get_user_constitution, generate_wellness_plan]
5.4 设计 ReAct Prompt 模板
from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template("""
你是一个专业的中医养生助手,名叫小甘草。你可以使用以下工具:
{tools}
工具名称:{tool_names}
请严格按照以下格式回答:
Question: 用户的问题
Thought: 思考需要做什么
Action: 工具名称(必须是 [{tool_names}] 之一)
Action Input: 工具的输入参数(JSON格式,例如 {{"user_id": "123"}})
Observation: 工具返回的结果
... (重复)
Final Answer: 最终回答
开始!
Question: {input}
Thought: {agent_scratchpad}
""")
5.5 创建 Agent 和执行器
from langchain.agents import AgentExecutor, create_react_agent
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 打印中间步骤
max_iterations=5,
handle_parsing_errors=True,
)
5.6 命令行测试
result = executor.invoke({"input": "用户ID是 test123,问题:我最近总是疲劳"})
print(result["output"])
输出示例:
> Entering new AgentExecutor chain...
Thought: 需要先查询用户体质。
Action: get_user_constitution
Action Input: {"user_id": "test123"}
Observation: 气虚质
Thought: 现在生成养生方案。
Action: generate_wellness_plan
Action Input: {"constitution": "气虚质"}
Observation: {"diet": "多吃山药", ...}
Final Answer: 您属于气虚质,建议多吃山药、黄芪...
六、阶段 3:FastAPI 服务封装
6.1 创建 FastAPI 应用
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["*"])
6.2 定义请求/响应模型
class ChatRequest(BaseModel):
user_id: str
message: str
class ChatResponse(BaseModel):
reply: str
6.3 实现 /chat 接口
@app.post("/chat", response_model=ChatResponse)
async def chat_endpoint(request: ChatRequest):
full_input = f"用户ID是 {request.user_id},问题:{request.message}"
result = executor.invoke({"input": full_input})
return ChatResponse(reply=result["output"])
6.4 添加健康检查与错误处理
@app.get("/health")
async def health():
return {"status": "ok"}
# 在接口内部添加 try-except 并记录日志
6.5 启动服务
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
6.6 测试(Postman 或 curl)
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"user_id": "test123", "message": "我最近总是疲劳"}'
七、踩坑与经验
7.1 模型不按格式输出
- 原因:本地小模型指令遵循能力弱。
- 解决:使用 DeepSeek API 或换用
llama3.2:1b;降低temperature;强化 Prompt。
7.2 LangChain 版本兼容性
create_react_agent在 LangChain 1.x 中已移除,需要使用 0.3.x 版本。- 建议使用 Python 3.10 环境安装
langchain==0.3.0。
7.3 工具函数缺少 docstring
@tool强制要求 docstring,否则报错。- 为每个工具补充清晰的三引号注释。
7.4 run() 方法弃用
AgentExecutor.run()在 0.3.x 中已弃用,改用invoke()并传入字典。
八、后续计划
- 完成工具函数的单元测试。
- 接入自训练 Qwen-7B 模型(LoRA)。
- 实现 RAG 知识库(ChromaDB + 自训嵌入模型)。
- 前端可视化 Agent 思考过程。
- 主动健康提醒(定时任务 + Agent 生成内容)。
九、总结
通过 LangChain 的 create_react_agent,我快速搭建了一个可用的 ReAct Agent,避免了手写循环的繁琐。结合 FastAPI 封装,Agent 能够轻松集成到现有的 Node.js 后端。整个过程虽然遇到不少坑,但收获巨大。
如果你也在构建类似的 AI Agent,欢迎留言交流。。
附录:环境要求
- Python 3.10+
- Ollama + qwen2:1.5b(或 DeepSeek API Key)
- 依赖见
requirements.txt
以上建议仅供参考,身体不适请及时咨询专业医师。
这样大纲就与你实际使用的方案一致了。你可以根据这个结构填充内容,并如实说明工具测试尚未完成。需要我帮你调整某个章节的细节吗?