2026-08-07
收藏夹
00
请注意,本文编写于 87 天前,最后修改于 87 天前,其中某些信息可能已经过时。

目录

AI Agent开发 + 大模型应用 + 具身智能:从入门到精通完整指南(2026版)
目录
方向A:大模型应用开发(RAG + 微调)
A.1 环境搭建(第1周)
目标:跑通第一个大模型 API 调用
本地部署(Ollama)
A.2 Prompt Engineering 系统训练(第2-3周)
示例1:Zero-shot → Few-shot → Chain-of-Thought 演进
Function Calling 实践
A.3 RAG 检索增强生成(第4-7周)⭐ 核心
完整的 RAG 系统实现
RAG 评估体系(Ragas)
A.4 模型微调 Fine-Tuning(第8-10周)
LoRA 微调实战
微调 vs RAG 决策树
方向B:AI Agent 开发
B.1 LangChain Agent 入门(第1-2周)
完整的 Function Calling Agent
B.2 LangGraph 核心实战(第3-5周)⭐⭐
示例1:带条件的 ReAct Agent 循环
示例2:Human-in-the-Loop(人工审批)
示例3:Multi-Agent Supervisor 模式
B.3 MCP 协议开发(第6-7周)
构建一个 MCP Server
MCP Client 调用
B.4 Agent 生产部署(第8-10周)
LangGraph Server 部署
方向C:具身智能
C.1 环境搭建(第1周)
第一个仿真程序
C.2 EI-Beginner 6阶段教程(第2-6周)
任务1:传统控制 —— PID 控制器
任务3:行为克隆(Behavior Cloning)
任务5:VLA(视觉-语言-动作)模型
C.3 强化学习 for Robotics(第7-9周)
PPO 训练机械臂抓取
C.4 Sim-to-Real 迁移(第10-12周)
域随机化(Domain Randomization)
C.5 具身智能学习资源汇总
综合项目实战
项目1:企业智能文档助手(组合 RAG + Agent)
项目2:自动化工作流 Agent
面试高频考点
RAG 方向
Agent 方向
学习检查清单
方向A(RAG + 微调)
方向B(AI Agent)
方向C(具身智能)

AI Agent开发 + 大模型应用 + 具身智能:从入门到精通完整指南(2026版)

适用人群:有 Python/后端基础,目标岗位为 AI 应用开发工程师、Agent 开发工程师、智能体全栈工程师 预计学习周期:3-6个月(脱产)/ 6-12个月(在职) 核心理念:每个阶段至少产出一个可展示的 GitHub 项目


目录


方向A:大模型应用开发(RAG + 微调)

A.1 环境搭建(第1周)

目标:跑通第一个大模型 API 调用

python
# 1. 安装依赖 # pip install openai python-dotenv # 2. 配置 API Key(.env 文件) # OPENAI_API_KEY=sk-xxx # OPENAI_BASE_URL=https://api.openai.com/v1 # 或其他兼容端点 import os import json from openai import OpenAI from dotenv import load_dotenv load_dotenv() client = OpenAI( api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL") ) # ===== 示例1:最基础的对话 ===== response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": "你是一个Python编程助手,回答要简洁,代码要有注释。"}, {"role": "user", "content": "用Python写一个装饰器,计算函数执行时间"} ], temperature=0.7, max_tokens=1024 ) print(response.choices[0].message.content) # ===== 示例2:流式输出 ===== stream = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "解释什么是Transformer的Self-Attention机制"}], stream=True ) for chunk in stream: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="", flush=True)

本地部署(Ollama)

bash
# 安装 Ollama 后 ollama pull deepseek-r1:7b # 推理模型 ollama pull qwen3:14b # 通义千问3 ollama pull llama4:8b # Meta最新 # Python 调用 # pip install ollama import ollama response = ollama.chat( model="qwen3:14b", messages=[{"role": "user", "content": "你好,介绍一下你自己"}] ) print(response["message"]["content"])

A.2 Prompt Engineering 系统训练(第2-3周)

示例1:Zero-shot → Few-shot → Chain-of-Thought 演进

python
# ===== Zero-shot(零样本) ===== prompt_zero = "将以下句子翻译成英文:今天天气真好。" # ===== Few-shot(少样本) ===== prompt_few = """将中文翻译成英文: 中文:我喜欢吃火锅。 英文:I like eating hot pot. 中文:明天要下雨。 英文:It will rain tomorrow. 中文:今天天气真好。 英文:""" # ===== Chain-of-Thought(思维链) ===== prompt_cot = """问题:一个水池,进水管3小时注满,出水管5小时排空。两管同时开,几小时注满? 让我们一步步思考: 1. 进水速率:1/3 池/小时 2. 出水速率:1/5 池/小时 3. 净进水速率:1/3 - 1/5 = 5/15 - 3/15 = 2/15 池/小时 4. 注满时间:1 ÷ (2/15) = 15/2 = 7.5 小时 答案:7.5小时 --- 问题:一个水池,进水管4小时注满,出水管6小时排空。两管同时开,几小时注满? 让我们一步步思考:""" # ===== ReAct 模式(Reasoning + Acting) ===== react_system_prompt = """你是一个能使用工具的AI助手。请按以下格式回答: Thought: 我需要思考什么? Action: 要调用的工具名 Action Input: 工具参数 Observation: 工具返回结果 ... (可重复) Thought: 我现在知道最终答案了 Final Answer: 最终回答 可用工具: - search(query: str): 搜索互联网 - calculate(expression: str): 数学计算 """ # ===== 结构化输出(JSON Schema) ===== response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "分析以下新闻的情感倾向:今天股市大涨,投资者信心十足"}], response_format={ "type": "json_schema", "json_schema": { "name": "sentiment_analysis", "schema": { "type": "object", "properties": { "sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]}, "confidence": {"type": "number", "minimum": 0, "maximum": 1}, "keywords": {"type": "array", "items": {"type": "string"}}, "summary": {"type": "string"} }, "required": ["sentiment", "confidence", "keywords", "summary"] } } } ) result = json.loads(response.choices[0].message.content) print(json.dumps(result, indent=2, ensure_ascii=False))

Function Calling 实践

python
# ===== 定义工具函数 ===== def get_weather(city: str, date: str = "今天") -> dict: """获取指定城市的天气信息""" # 模拟天气数据(实际应调用天气API) weather_data = { "北京": {"今天": "晴,25°C~32°C,北风3级", "明天": "多云,23°C~30°C"}, "上海": {"今天": "小雨,26°C~31°C", "明天": "阴,24°C~29°C"}, } return {"city": city, "date": date, "weather": weather_data.get(city, {}).get(date, "无数据")} # ===== Function Calling 调用 ===== tools = [{ "type": "function", "function": { "name": "get_weather", "description": "获取指定城市的天气信息", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "城市名称,如'北京'"}, "date": {"type": "string", "description": "日期,如'今天'或'明天'"} }, "required": ["city"] } } }] response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "北京明天天气怎么样?适合出门吗?"}], tools=tools, tool_choice="auto" ) # 处理工具调用 tool_calls = response.choices[0].message.tool_calls if tool_calls: for tool_call in tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments) if func_name == "get_weather": result = get_weather(**func_args) print(f"工具调用: {func_name}({func_args})") print(f"返回结果: {result}")

A.3 RAG 检索增强生成(第4-7周)⭐ 核心

完整的 RAG 系统实现

python
# pip install langchain langchain-openai langchain-community chromadb pypdf tiktoken # pip install sentence-transformers # 本地 embedding # ========================================== # Step 1: 文档加载与处理 # ========================================== from langchain_community.document_loaders import PyPDFLoader, TextLoader, DirectoryLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma import os # 加载文档 loader = DirectoryLoader( "./documents/", glob="**/*.pdf", loader_cls=PyPDFLoader, show_progress=True ) documents = loader.load() print(f"加载了 {len(documents)} 页文档") # 智能分块(2026最佳实践:语义分块 + 重叠) text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, # 每块1000字符 chunk_overlap=200, # 重叠200字符,保持上下文连贯 separators=["\n\n", "\n", "。", "!", "?", ";", ".", "!", "?", ";", " ", ""], length_function=len, ) chunks = text_splitter.split_documents(documents) print(f"分割为 {len(chunks)} 个文本块") # ========================================== # Step 2: 向量化与存储 # ========================================== embeddings = OpenAIEmbeddings(model="text-embedding-3-large") # 3072维 # 创建向量数据库(持久化到本地) vectorstore = Chroma.from_documents( documents=chunks, embedding=embeddings, persist_directory="./chroma_db", collection_name="my_knowledge_base" ) print(f"向量数据库已创建,包含 {vectorstore._collection.count()} 条记录") # ========================================== # Step 3: 高级检索策略 # ========================================== from langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import CrossEncoderReranker from langchain_community.cross_encoders import HuggingFaceCrossEncoder # 多策略检索器 retriever = vectorstore.as_retriever( search_type="mmr", # MMR: 最大边际相关性,平衡相关性和多样性 search_kwargs={ "k": 20, # 初检索取20条 "fetch_k": 50, # 从50条中筛选 "lambda_mult": 0.7 # 相关性权重(0=最大多样性, 1=最大相关性) } ) # Rerank 重排序(提升精度关键) model = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-v2-m3") compressor = CrossEncoderReranker(model=model, top_n=5) compression_retriever = ContextualCompressionRetriever( base_compressor=compressor, base_retriever=retriever ) # 查询改写(Query Rewriting) def rewrite_query(original_query: str, chat_history: list = None) -> str: """将模糊查询改写为精确的检索查询""" history_context = "" if chat_history: history_context = "\n".join([f"用户: {h['user']}\n助手: {h['assistant']}" for h in chat_history[-3:]]) response = client.chat.completions.create( model="gpt-4o", messages=[{ "role": "system", "content": "你是一个查询优化器。将用户的原始问题改写为一个精确的、适合向量检索的查询语句。" "如果用户使用了代词(如'它'、'这个'),请根据对话历史替换为具体的实体。" }, { "role": "user", "content": f"对话历史:\n{history_context}\n\n原始问题: {original_query}\n\n优化后的查询:" }], temperature=0.1 ) return response.choices[0].message.content.strip() # ========================================== # Step 4: RAG 生成链 # ========================================== from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser llm = ChatOpenAI(model="gpt-4o", temperature=0.3) RAG_PROMPT = ChatPromptTemplate.from_messages([ ("system", """你是一个基于知识库的问答助手。请严格根据提供的参考资料回答问题。 规则: 1. 如果参考资料中包含答案,请直接引用并注明来源 2. 如果参考资料不包含答案,请明确说"根据现有资料无法回答" 3. 回答要简洁、准确,使用编号列表组织多个要点 4. 在每个要点后标注来源文档名和片段编号 参考资料: {context}"""), ("human", "{question}") ]) def format_docs(docs): return "\n\n---\n\n".join([ f"[来源{i+1}] 文档: {doc.metadata.get('source', '未知')}\n{doc.page_content}" for i, doc in enumerate(docs) ]) # 构建 RAG 链 rag_chain = ( { "context": compression_retriever | format_docs, "question": RunnablePassthrough() } | RAG_PROMPT | llm | StrOutputParser() ) # ========================================== # Step 5: 完整问答流程(含评估) # ========================================== def ask_with_rag(question: str, chat_history: list = None) -> dict: """完整的RAG问答流程""" # 1. 查询改写 optimized_query = rewrite_query(question, chat_history) print(f"原始问题: {question}") print(f"优化查询: {optimized_query}") # 2. 检索 + 生成 answer = rag_chain.invoke(optimized_query) # 3. 获取检索到的文档(用于评估) retrieved_docs = compression_retriever.invoke(optimized_query) return { "question": question, "optimized_query": optimized_query, "answer": answer, "sources": [ { "content": doc.page_content[:200], "source": doc.metadata.get("source", "未知"), "page": doc.metadata.get("page", "N/A") } for doc in retrieved_docs ] } # 使用示例 result = ask_with_rag("公司今年的绩效考核标准是什么?") print(result["answer"]) print(f"\n来源: {json.dumps(result['sources'], indent=2, ensure_ascii=False)}")

RAG 评估体系(Ragas)

python
# pip install ragas datasets from ragas import evaluate from ragas.metrics import ( faithfulness, # 忠实度:答案是否忠于检索到的上下文 answer_relevancy, # 答案相关性 context_precision, # 上下文精确率 context_recall, # 上下文召回率 context_entity_recall # 实体召回率 ) from datasets import Dataset # 构建评估数据集 eval_data = Dataset.from_dict({ "question": [ "什么是RAG?", "如何优化向量检索的召回率?", "LangChain和LlamaIndex的区别是什么?" ], "answer": [ "RAG(Retrieval-Augmented Generation)是一种...", "优化召回率的方法包括混合检索...", "LangChain是通用框架,LlamaIndex专注于..." ], "contexts": [ ["RAG是一种结合检索和生成的AI技术..."], ["混合检索结合向量检索和BM25..."], ["LangChain提供全链路工具,LlamaIndex侧重索引..."] ], "ground_truth": [ "RAG是检索增强生成技术,通过检索外部知识来增强LLM的回答质量", "可以通过混合检索、查询改写、Rerank重排序来提升召回率", "LangChain是通用LLM应用框架,LlamaIndex专注于数据索引和检索" ] }) # 执行评估 scores = evaluate( eval_data, metrics=[faithfulness, answer_relevancy, context_precision, context_recall] ) print(scores)

A.4 模型微调 Fine-Tuning(第8-10周)

LoRA 微调实战

python
# ========================================== # 使用 QLoRA 微调 Qwen2.5-7B(消费级显卡可跑) # ========================================== # pip install transformers peft datasets accelerate bitsandbytes torch import torch from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, BitsAndBytesConfig, DataCollatorForSeq2Seq ) from peft import LoraConfig, get_peft_model, TaskType, prepare_model_for_kbit_training from datasets import Dataset # ===== 1. 准备微调数据 ===== # 数据格式:指令微调的标准格式 training_data = [ { "instruction": "你是一个医疗问诊助手。请根据患者描述给出初步建议。", "input": "我最近总是头痛,特别是下午,有时候还会恶心。", "output": "根据您的描述(下午头痛+恶心),可能的原因包括:\n1. 紧张性头痛:长时间工作导致颈肩肌肉紧张\n2. 视疲劳:长时间盯屏幕\n3. 血压波动:下午血压可能升高\n\n建议:\n- 每工作1小时休息5-10分钟\n- 检查视力,调整屏幕亮度和距离\n- 监测下午血压\n- 如症状持续加重,请及时就医\n\n⚠️ 以上仅为初步分析,不能替代医生诊断。" }, # ... 至少准备500-1000条高质量数据 ] def format_instruction(sample): """将数据格式化为对话模板""" return { "text": f"<|im_start|>system\n{sample['instruction']}<|im_end|>\n" f"<|im_start|>user\n{sample['input']}<|im_end|>\n" f"<|im_start|>assistant\n{sample['output']}<|im_end|>" } dataset = Dataset.from_list(training_data) dataset = dataset.map(format_instruction) # ===== 2. 加载模型(4bit量化) ===== model_name = "Qwen/Qwen2.5-7B-Instruct" bnb_config = BitsAndBytesConfig( load_in_4bit=True, # 4bit量化 bnb_4bit_quant_type="nf4", # NF4量化类型 bnb_4bit_compute_dtype=torch.bfloat16, # 计算精度 bnb_4bit_use_double_quant=True # 双重量化,进一步节省显存 ) model = AutoModelForCausalLM.from_pretrained( model_name, quantization_config=bnb_config, device_map="auto", # 自动分配到GPU trust_remote_code=True ) tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) tokenizer.pad_token = tokenizer.eos_token # 准备模型用于k-bit训练 model = prepare_model_for_kbit_training(model) # ===== 3. 配置 LoRA ===== lora_config = LoraConfig( task_type=TaskType.CAUSAL_LM, r=16, # LoRA秩(rank),越大模型能力越强但越慢 lora_alpha=32, # LoRA缩放参数,通常设为2*r lora_dropout=0.1, # Dropout防止过拟合 target_modules=[ # 目标模块(不同模型名称不同) "q_proj", "k_proj", "v_proj", "o_proj", # Attention层 "gate_proj", "up_proj", "down_proj" # FFN层 ], bias="none" ) model = get_peft_model(model, lora_config) model.print_trainable_parameters() # 查看可训练参数占比(通常<1%) # ===== 4. 训练 ===== training_args = TrainingArguments( output_dir="./qwen2.5-lora-medical", num_train_epochs=3, per_device_train_batch_size=4, gradient_accumulation_steps=4, # 有效batch_size = 4*4 = 16 learning_rate=2e-4, warmup_ratio=0.03, logging_steps=10, save_steps=200, save_total_limit=3, fp16=True, optim="paged_adamw_8bit", report_to="none" ) trainer = Trainer( model=model, args=training_args, train_dataset=dataset, data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True) ) # 开始训练(7B模型+QLoRA在RTX4090上约需3-6小时) trainer.train() # ===== 5. 保存与推理 ===== model.save_pretrained("./qwen2.5-lora-medical-final") tokenizer.save_pretrained("./qwen2.5-lora-medical-final") # 加载并推理 from peft import PeftModel base_model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto") model = PeftModel.from_pretrained(base_model, "./qwen2.5-lora-medical-final") inputs = tokenizer( "<|im_start|>system\n你是一个医疗问诊助手。<|im_end|>\n<|im_start|>user\n我最近失眠严重,怎么办?<|im_end|>\n<|im_start|>assistant\n", return_tensors="pt" ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=512, temperature=0.7) print(tokenizer.decode(outputs[0], skip_special_tokens=True))

微调 vs RAG 决策树

是否需要引入最新/私有知识? ├── 是 → 用 RAG └── 否 → 是否需要固化风格/格式? ├── 是 → 用 微调(LoRA) └── 否 → 用 Prompt Engineering 即可 实际项目中:90% = Prompt + RAG,10% = Prompt + RAG + 微调

方向B:AI Agent 开发

B.1 LangChain Agent 入门(第1-2周)

完整的 Function Calling Agent

python
# pip install langchain langchain-openai langchain-community from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_functions_agent from langchain.tools import tool from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_community.tools import DuckDuckGoSearchRun, WikipediaQueryRun from langchain_community.utilities import WikipediaAPIWrapper import datetime import json # ===== 1. 定义工具 ===== @tool def get_current_time(format: str = "%Y-%m-%d %H:%M:%S") -> str: """获取当前日期和时间。format参数可指定时间格式""" return datetime.datetime.now().strftime(format) @tool def calculate(expression: str) -> str: """执行数学计算。expression是数学表达式,如'2+3*4'或'sqrt(16)'""" import math try: # 安全的数学计算(仅允许数学函数) allowed_names = {k: v for k, v in math.__dict__.items() if not k.startswith("__")} result = eval(expression, {"__builtins__": {}}, allowed_names) return f"计算结果: {result}" except Exception as e: return f"计算错误: {str(e)}" @tool def save_note(content: str, filename: str = None) -> str: """保存内容到本地文本文件。content是要保存的内容""" if not filename: filename = f"note_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.txt" with open(filename, "w", encoding="utf-8") as f: f.write(content) return f"已保存到 {filename}" # 搜索工具 search = DuckDuckGoSearchRun() wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()) # 工具集 tools = [get_current_time, calculate, save_note, search, wikipedia] # ===== 2. 创建 Agent ===== llm = ChatOpenAI(model="gpt-4o", temperature=0) # Agent 系统提示词 system_prompt = """你是一个全能的AI助手,可以使用各种工具来完成任务。 核心原则: 1. 对于需要实时信息的问题,使用搜索工具 2. 对于数学计算,使用计算工具 3. 需要保存重要信息时,使用笔记工具 4. 在回答中说明你使用了哪些工具,以及为什么 5. 如果多个工具能解决问题,选择最直接的那个 6. 如果一个工具的结果不够,可以组合使用多个工具 你的名字是"Jarvis",请用中文回答。""" prompt = ChatPromptTemplate.from_messages([ ("system", system_prompt), MessagesPlaceholder(variable_name="chat_history", optional=True), ("human", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad") ]) agent = create_openai_functions_agent(llm, tools, prompt) agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True, # 打印思考过程 max_iterations=10, # 最大工具调用次数 handle_parsing_errors=True, # 处理解析错误 return_intermediate_steps=True ) # ===== 3. 运行 Agent ===== result = agent_executor.invoke({ "input": "搜索2026年诺贝尔物理学奖得主,计算他们的平均年龄,然后把结果保存到文件。" }) print(f"\n最终答案:\n{result['output']}") print(f"\n中间步骤:") for step in result["intermediate_steps"]: action, observation = step print(f" 工具: {action.tool}") print(f" 输入: {action.tool_input}") print(f" 输出: {str(observation)[:200]}...") print()

B.2 LangGraph 核心实战(第3-5周)⭐⭐

示例1:带条件的 ReAct Agent 循环

python
# pip install langgraph langgraph-checkpoint from typing import TypedDict, Annotated, Literal from langgraph.graph import StateGraph, END, START from langgraph.graph.message import add_messages from langgraph.checkpoint.memory import MemorySaver from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, AIMessage, ToolMessage from langchain.tools import tool import operator # ===== 1. 定义状态 ===== class AgentState(TypedDict): messages: Annotated[list, add_messages] # 消息列表(自动追加) iteration_count: int # 迭代计数(防止死循环) # ===== 2. 定义节点 ===== llm = ChatOpenAI(model="gpt-4o", temperature=0) @tool def weather(city: str) -> str: """查询城市天气""" return f"{city}今天晴,22°C~30°C" @tool def web_search(query: str) -> str: """网络搜索""" return f"关于'{query}'的搜索结果:..." tools = [weather, web_search] llm_with_tools = llm.bind_tools(tools) def agent_node(state: AgentState) -> AgentState: """Agent节点:调用LLM,决定下一步""" response = llm_with_tools.invoke(state["messages"]) return { "messages": [response], "iteration_count": state["iteration_count"] + 1 } def tool_node(state: AgentState) -> AgentState: """工具节点:执行工具调用""" messages = state["messages"] last_message = messages[-1] tool_messages = [] for tool_call in last_message.tool_calls: tool_name = tool_call["name"] tool_args = tool_call["args"] # 找到对应的工具并执行 for tool in tools: if tool.name == tool_name: result = tool.invoke(tool_args) break tool_messages.append( ToolMessage(content=str(result), tool_call_id=tool_call["id"]) ) return {"messages": tool_messages, "iteration_count": state["iteration_count"]} # ===== 3. 条件路由 ===== def should_continue(state: AgentState) -> Literal["tools", "end"]: """判断下一步:继续调用工具 or 结束""" messages = state["messages"] last_message = messages[-1] # 防止无限循环 if state["iteration_count"] >= 15: return "end" # 如果有工具调用,继续 if hasattr(last_message, "tool_calls") and last_message.tool_calls: return "tools" return "end" # ===== 4. 构建图 ===== workflow = StateGraph(AgentState) workflow.add_node("agent", agent_node) workflow.add_node("tools", tool_node) workflow.add_edge(START, "agent") workflow.add_conditional_edges( "agent", should_continue, {"tools": "tools", "end": END} ) workflow.add_edge("tools", "agent") # 编译(带内存检查点) memory = MemorySaver() app = workflow.compile(checkpointer=memory) # ===== 5. 运行 ===== config = {"configurable": {"thread_id": "user-123"}} result = app.invoke( {"messages": [HumanMessage(content="北京天气怎么样?用搜索查一下明天的天气")], "iteration_count": 0}, config=config ) for msg in result["messages"]: if isinstance(msg, AIMessage): print(f"AI: {msg.content}") elif hasattr(msg, "tool_calls") and msg.tool_calls: print(f"调用工具: {[tc['name'] for tc in msg.tool_calls]}")

示例2:Human-in-the-Loop(人工审批)

python
from langgraph.types import interrupt, Command class ApprovalState(TypedDict): content: str # 待审批内容 approved: bool # 是否批准 final_output: str # 最终输出 def generate_content(state: ApprovalState) -> ApprovalState: """生成内容""" return { "content": f"这是自动生成的邮件草稿:\n\n尊敬的客户:\n感谢您的咨询...\n\n请审批。" } def human_approval(state: ApprovalState) -> ApprovalState: """人工审批节点 —— 这里会暂停等人类操作""" # interrupt() 会暂停图执行,返回当前状态给调用者 # 人类审批后通过 Command(resume=...) 继续 approval_result = interrupt({ "message": "请审批以上内容", "content": state["content"], "action": "approve_or_reject" }) # approval_result 是人工传入的值 return {"approved": approval_result.get("approved", False)} def post_process(state: ApprovalState) -> ApprovalState: """后处理""" if state["approved"]: return {"final_output": f"✅ 已发送:\n{state['content']}"} else: return {"final_output": "❌ 审批未通过,内容已丢弃"} # 构建图 workflow_approval = StateGraph(ApprovalState) workflow_approval.add_node("generate", generate_content) workflow_approval.add_node("approve", human_approval) workflow_approval.add_node("process", post_process) workflow_approval.add_edge(START, "generate") workflow_approval.add_edge("generate", "approve") workflow_approval.add_edge("approve", "process") workflow_approval.add_edge("process", END) app_approval = workflow_approval.compile() # === 调用方代码 === # 第一次调用:运行到审批节点时暂停 config = {"configurable": {"thread_id": "approval-001"}} # 首次运行 —— 会在 human_approval 节点暂停 try: result = app_approval.invoke( {"content": "", "approved": False, "final_output": ""}, config=config ) except Exception as e: print(f"暂停等待审批: {e}") # 人工审批后恢复 # resumed = app_approval.invoke(Command(resume={"approved": True}), config=config) # print(resumed["final_output"])

示例3:Multi-Agent Supervisor 模式

python
from typing import Literal from langgraph.graph import StateGraph, END from langgraph.graph.message import add_messages from langgraph.checkpoint.memory import MemorySaver # ===== 定义 Agent 角色 ===== RESEARCHER_PROMPT = """你是研究员Agent。职责: 1. 搜索和收集信息 2. 提供数据支撑和事实引用 3. 不发表观点,只提供事实 可用工具: web_search""" WRITER_PROMPT = """你是写手Agent。职责: 1. 根据研究员提供的信息撰写内容 2. 确保文章结构清晰、语言流畅 3. 可要求研究员补充更多信息""" CRITIC_PROMPT = """你是审稿Agent。职责: 1. 审核写手的内容质量 2. 检查事实准确性、逻辑一致性 3. 指出问题并要求修改 标准:内容准确、逻辑清晰、无冗余""" # ===== Supervisor 状态 ===== class SupervisorState(TypedDict): messages: Annotated[list, add_messages] next_agent: str task: str # 原始任务 research_complete: bool draft_complete: bool review_complete: bool iteration: int # 审稿轮次 # ===== Supervisor 节点 ===== def supervisor_node(state: SupervisorState) -> SupervisorState: """主管Agent:协调各子Agent的工作""" # 防止无限审稿循环 if state["iteration"] >= 3: return {"next_agent": "FINISH", "review_complete": True} supervisor_prompt = f"""你是项目主管。当前任务:{state['task']} 状态: - 资料搜集: {'完成' if state['research_complete'] else '未完成'} - 初稿撰写: {'完成' if state['draft_complete'] else '未完成'} - 审稿次数: {state['iteration']} 请决定下一步由谁工作。选项: - RESEARCHER: 搜集更多资料 - WRITER: 撰写/修改文章 - CRITIC: 审稿 - FINISH: 任务完成""" response = llm.invoke([ HumanMessage(content=supervisor_prompt) ]) return {"next_agent": response.content.strip()} # ===== 构建 Supervisor 图 ===== supervisor_graph = StateGraph(SupervisorState) # 添加节点 supervisor_graph.add_node("supervisor", supervisor_node) supervisor_graph.add_node("researcher", researcher_node) supervisor_graph.add_node("writer", writer_node) supervisor_graph.add_node("critic", critic_node) # 路由函数 def route_to_agent(state: SupervisorState) -> str: return state["next_agent"].lower() supervisor_graph.add_edge(START, "supervisor") supervisor_graph.add_conditional_edges("supervisor", route_to_agent, { "researcher": "researcher", "writer": "writer", "critic": "critic", "finish": END }) # 每个子Agent完成后回到supervisor supervisor_graph.add_edge("researcher", "supervisor") supervisor_graph.add_edge("writer", "supervisor") supervisor_graph.add_edge("critic", "supervisor") app_supervisor = supervisor_graph.compile() # 运行 result = app_supervisor.invoke({ "messages": [HumanMessage(content="写一篇关于AI Agent发展趋势的博客文章")], "task": "写一篇关于2026年AI Agent发展趋势的博客文章(约1000字)", "iteration": 0, "research_complete": False, "draft_complete": False, "review_complete": False, "next_agent": "supervisor" })

B.3 MCP 协议开发(第6-7周)

构建一个 MCP Server

python
# ========================================== # MCP Server 示例:天气服务 # pip install mcp # ========================================== # weather_server.py import asyncio import json from mcp.server import Server, NotificationOptions from mcp.server.models import InitializationCapabilities from mcp.server.stdio import stdio_server from mcp.types import Tool, TextContent, Resource, ResourceTemplate # 创建 MCP Server server = Server("weather-service") # ===== 注册工具 ===== @server.list_tools() async def list_tools() -> list[Tool]: return [ Tool( name="get_weather", description="获取指定城市的实时天气信息", inputSchema={ "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,如'北京'、'上海'" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位", "default": "celsius" } }, "required": ["city"] } ), Tool( name="get_forecast", description="获取未来7天天气预报", inputSchema={ "type": "object", "properties": { "city": {"type": "string", "description": "城市名称"}, "days": { "type": "integer", "minimum": 1, "maximum": 7, "default": 3 } }, "required": ["city"] } ) ] @server.call_tool() async def call_tool(name: str, arguments: dict) -> list[TextContent]: """处理工具调用""" if name == "get_weather": city = arguments["city"] unit = arguments.get("unit", "celsius") # 模拟天气API调用 weather_data = { "北京": {"temp": 25, "humidity": 45, "condition": "晴", "wind": "北风3级"}, "上海": {"temp": 28, "humidity": 70, "condition": "小雨", "wind": "东风2级"}, } data = weather_data.get(city, {"temp": 22, "humidity": 55, "condition": "多云", "wind": "微风"}) temp = data["temp"] if unit == "celsius" else data["temp"] * 9/5 + 32 return [TextContent( type="text", text=f"{city}天气: {data['condition']}\n温度: {temp}°{'C' if unit == 'celsius' else 'F'}\n" f"湿度: {data['humidity']}%\n风力: {data['wind']}" )] elif name == "get_forecast": city = arguments["city"] days = arguments.get("days", 3) # 模拟预报 forecast = "\n".join([ f"第{i+1}天: {'晴' if i%2==0 else '多云'} {22+i}°C" for i in range(days) ]) return [TextContent(type="text", text=f"{city}未来{days}天预报:\n{forecast}")] raise ValueError(f"未知工具: {name}") # ===== 注册资源(可被客户端读取的数据) ===== @server.list_resources() async def list_resources() -> list[Resource]: return [ Resource( uri="weather://cities", name="支持的城市列表", description="本服务支持查询的城市", mimeType="application/json" ) ] @server.read_resource() async def read_resource(uri: str) -> str: if uri == "weather://cities": return json.dumps(["北京", "上海", "广州", "深圳", "杭州", "成都", "武汉"], ensure_ascii=False) raise ValueError(f"未知资源: {uri}") # ===== 启动服务 ===== async def main(): async with stdio_server() as (read_stream, write_stream): await server.run( read_stream, write_stream, InitializationCapabilities( sampling={}, experimental={}, roots={} ), notification_options=NotificationOptions() ) if __name__ == "__main__": asyncio.run(main())

MCP Client 调用

python
# ========================================== # MCP Client:在 LangChain Agent 中使用 MCP 工具 # ========================================== import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client from langchain_mcp import MCPToolkit async def create_mcp_agent(): # 连接 MCP Server server_params = StdioServerParameters( command="python", args=["weather_server.py"] ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: # 初始化会话 await session.initialize() # 获取 MCP 工具 toolkit = MCPToolkit(session=session) tools = await toolkit.get_tools() # 创建 Agent from langgraph.prebuilt import create_react_agent agent = create_react_agent( model=ChatOpenAI(model="gpt-4o"), tools=tools ) # 运行 result = await agent.ainvoke({ "messages": [HumanMessage(content="北京今天天气怎么样?适合户外运动吗?")] }) print(result["messages"][-1].content) asyncio.run(create_mcp_agent())

B.4 Agent 生产部署(第8-10周)

LangGraph Server 部署

json
// langgraph.json —— 部署配置 { "dependencies": ["."], "graphs": { "weather_agent": "./src/weather_agent.py:app", "multi_agent": "./src/supervisor.py:app_supervisor" }, "env": ".env", "python_version": "3.12" }
yaml
# docker-compose.yml version: '3.8' services: langgraph-api: image: langgraph-api:latest ports: - "8000:8000" environment: - OPENAI_API_KEY=${OPENAI_API_KEY} - LANGCHAIN_TRACING_V2=true - LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY} volumes: - ./chroma_db:/app/chroma_db - ./models:/app/models restart: always
python
# FastAPI 包装 Agent 为 REST API # app.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from langgraph.checkpoint.memory import MemorySaver import uuid app = FastAPI(title="AI Agent API") class ChatRequest(BaseModel): message: str thread_id: str = None class ChatResponse(BaseModel): answer: str thread_id: str tool_calls: list = [] # 全局Agent实例 agent_app = create_agent_app() # 你的LangGraph应用 @app.post("/chat", response_model=ChatResponse) async def chat(request: ChatRequest): thread_id = request.thread_id or str(uuid.uuid4()) config = {"configurable": {"thread_id": thread_id}} try: result = await agent_app.ainvoke( {"messages": [HumanMessage(content=request.message)], "iteration_count": 0}, config=config ) # 提取工具调用 tool_calls = [] for msg in result.get("messages", []): if hasattr(msg, "tool_calls") and msg.tool_calls: tool_calls.extend([tc["name"] for tc in msg.tool_calls]) return ChatResponse( answer=result["messages"][-1].content, thread_id=thread_id, tool_calls=tool_calls ) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.get("/health") async def health(): return {"status": "healthy"}

方向C:具身智能

C.1 环境搭建(第1周)

bash
# 安装仿真环境(无需硬件) pip install mujoco gymnasium stable-baselines3 torch # 安装 LeRobot(HuggingFace机器人框架) pip install lerobot # 零基础入门工具:zero2robot(完全浏览器内运行) git clone https://github.com/kaushikb11/zero2robot.git cd zero2robot uv sync

第一个仿真程序

python
# ========================================== # 示例1:经典倒立摆(强化学习入门) # ========================================== import gymnasium as gym import numpy as np env = gym.make("CartPole-v1", render_mode="human") for episode in range(5): state, info = env.reset() total_reward = 0 done = False while not done: # 随机策略(先看看效果) action = env.action_space.sample() state, reward, terminated, truncated, info = env.step(action) total_reward += reward done = terminated or truncated print(f"Episode {episode+1}: 总奖励 = {total_reward}") env.close() # ========================================== # 示例2:MuJoCo 机械臂仿真 # ========================================== import mujoco import mujoco.viewer import numpy as np # 加载一个简单的机械臂模型 xml = """ <mujoco> <worldbody> <light pos="0 0 3"/> <body pos="0 0 0"> <joint type="hinge" axis="0 0 1"/> <geom type="box" size=".5 .1 .05" rgba=".8 .2 .2 1"/> <body pos="1 0 0"> <joint type="hinge" axis="0 0 1"/> <geom type="box" size=".3 .05 .03" rgba=".2 .8 .2 1"/> </body> </body> </worldbody> </mujoco> """ model = mujoco.MjModel.from_xml_string(xml) data = mujoco.MjData(model) # 简单控制循环 for i in range(1000): # 施加正弦控制信号 data.ctrl[0] = np.sin(i * 0.1) # 第一个关节 data.ctrl[1] = np.cos(i * 0.1) # 第二个关节 mujoco.mj_step(model, data) if i % 100 == 0: print(f"Step {i}: 关节角度 = {data.qpos.round(3)}") print("仿真完成!")

C.2 EI-Beginner 6阶段教程(第2-6周)

基于复旦大学 OpenMOSS Lab 的 EI-Beginner 教程

任务1:传统控制 —— PID 控制器

python
# ========================================== # 双臂机器人 PID 轨迹跟踪 # ========================================== import numpy as np class PIDController: """PID 控制器""" def __init__(self, kp, ki, kd, dt): self.kp = kp self.ki = ki self.kd = kd self.dt = dt self.prev_error = 0 self.integral = 0 def compute(self, target, current): error = target - current self.integral += error * self.dt derivative = (error - self.prev_error) / self.dt output = self.kp * error + self.ki * self.integral + self.kd * derivative self.prev_error = error return output # 使用 PID 控制机械臂到达目标位置 def pid_arm_control(target_angles, current_angles, dt=0.01): """PID控制双臂到达目标角度""" pid_joints = [PIDController(kp=10.0, ki=0.1, kd=1.0, dt=dt) for _ in range(6)] trajectory = [current_angles.copy()] current = current_angles.copy() for step in range(500): for j, pid in enumerate(pid_joints): torque = pid.compute(target_angles[j], current[j]) # 简化的动力学更新 current[j] += torque * dt trajectory.append(current.copy()) # 检查是否到达目标 if np.allclose(current, target_angles, atol=0.01): print(f"到达目标,步数: {step}") break return np.array(trajectory) # 使用 current = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) target = np.array([0.5, -0.3, 0.0, 1.0, -0.5, 0.8]) traj = pid_arm_control(target, current)

任务3:行为克隆(Behavior Cloning)

python
# ========================================== # 从人类示教数据学习策略 # ========================================== import torch import torch.nn as nn from torch.utils.data import Dataset, DataLoader # 示教数据集(通常通过遥操作或VR设备采集) class DemonstrationDataset(Dataset): def __init__(self, observations, actions): """ observations: (N, obs_dim) —— 机械臂关节角度、目标位置等 actions: (N, action_dim) —— 关节力矩或目标角度 """ self.obs = torch.FloatTensor(observations) self.actions = torch.FloatTensor(actions) def __len__(self): return len(self.obs) def __getitem__(self, idx): return self.obs[idx], self.actions[idx] # 策略网络 class BehaviorCloningPolicy(nn.Module): def __init__(self, obs_dim, action_dim, hidden_dim=256): super().__init__() self.net = nn.Sequential( nn.Linear(obs_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, action_dim), ) def forward(self, obs): return self.net(obs) # 训练 def train_bc(demos: DemonstrationDataset, epochs=100): dataloader = DataLoader(demos, batch_size=64, shuffle=True) policy = BehaviorCloningPolicy(obs_dim=12, action_dim=6) optimizer = torch.optim.Adam(policy.parameters(), lr=1e-3) criterion = nn.MSELoss() for epoch in range(epochs): total_loss = 0 for obs, action in dataloader: pred_action = policy(obs) loss = criterion(pred_action, action) optimizer.zero_grad() loss.backward() optimizer.step() total_loss += loss.item() if epoch % 10 == 0: print(f"Epoch {epoch}: Loss = {total_loss/len(dataloader):.6f}") return policy # 部署 def deploy_policy(policy, env, num_episodes=5): """在仿真环境中部署训练好的策略""" successes = 0 for ep in range(num_episodes): obs, _ = env.reset() done = False while not done: with torch.no_grad(): action = policy(torch.FloatTensor(obs)).numpy() obs, reward, terminated, truncated, _ = env.step(action) done = terminated or truncated if terminated: successes += 1 print(f"成功率: {successes}/{num_episodes} ({successes/num_episodes*100:.1f}%)")

任务5:VLA(视觉-语言-动作)模型

python
# ========================================== # 使用 OpenVLA 进行多模态机器人控制 # ========================================== # pip install transformers torch pillow from transformers import AutoModelForVision2Seq, AutoProcessor from PIL import Image import torch # 加载 OpenVLA 模型(开源VLA模型) model = AutoModelForVision2Seq.from_pretrained( "openvla/openvla-7b", torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True ) processor = AutoProcessor.from_pretrained("openvla/openvla-7b") def vla_predict(image: Image.Image, instruction: str) -> dict: """ 输入:RGB图像 + 自然语言指令 输出:机械臂动作(7维:xyz位移 + 旋转 + 夹爪开合度) """ # 构建提示 prompt = f"In: What action should the robot take to {instruction}?\nOut:" # 处理输入 inputs = processor( text=prompt, images=image, return_tensors="pt" ).to(model.device, dtype=torch.bfloat16) # 推理 with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=50, do_sample=False ) # 解析动作 action_text = processor.decode(outputs[0], skip_special_tokens=True) # 解析7维动作向量(格式因模型而异) action = parse_action_from_text(action_text) return { "action": action, # [dx, dy, dz, droll, dpitch, dyaw, gripper] "raw_output": action_text } def parse_action_from_text(text: str): """从模型输出中解析动作向量""" import re # 匹配类似 [0.1, -0.05, 0.02, ...] 的格式 pattern = r'\[([^\]]+)\]' match = re.search(pattern, text) if match: nums = [float(x.strip()) for x in match.group(1).split(',')] return nums return [0.0] * 7 # 使用示例(需要在仿真或真机环境) # image = capture_camera_image() # 获取当前图像 # result = vla_predict(image, "pick up the red cube") # robot.execute_action(result["action"])

C.3 强化学习 for Robotics(第7-9周)

PPO 训练机械臂抓取

python
# ========================================== # 使用 PPO 训练机械臂抓取策略 # ========================================== import gymnasium as gym from stable_baselines3 import PPO from stable_baselines3.common.env_checker import check_env from stable_baselines3.common.callbacks import EvalCallback from stable_baselines3.common.monitor import Monitor import numpy as np # 使用标准的机械臂环境 # pip install gymnasium-robotics import gymnasium_robotics gymnasium_robotics.register_robotics_envs() # 创建环境 env = gym.make("FetchReach-v3", render_mode="rgb_array") check_env(env) # 验证环境接口 # 创建 PPO 模型 model = PPO( policy="MultiInputPolicy", # 处理字典观测空间 env=env, learning_rate=3e-4, n_steps=2048, batch_size=64, n_epochs=10, gamma=0.99, gae_lambda=0.95, clip_range=0.2, ent_coef=0.01, # 熵系数,鼓励探索 verbose=1, tensorboard_log="./ppo_fetch_tensorboard/" ) # 评估回调 eval_env = Monitor(gym.make("FetchReach-v3")) eval_callback = EvalCallback( eval_env, best_model_save_path="./ppo_fetch_best/", log_path="./ppo_fetch_logs/", eval_freq=10000, n_eval_episodes=10, deterministic=True ) # 训练(约需 1M steps,RTX4090 约 2-4 小时) model.learn( total_timesteps=1_000_000, callback=eval_callback, progress_bar=True ) model.save("ppo_fetch_reach_final") # ===== 推理 ===== model = PPO.load("ppo_fetch_reach_final") obs, _ = env.reset() for _ in range(100): action, _ = model.predict(obs, deterministic=True) obs, reward, terminated, truncated, _ = env.step(action) if terminated or truncated: obs, _ = env.reset()

C.4 Sim-to-Real 迁移(第10-12周)

域随机化(Domain Randomization)

python
# ========================================== # 域随机化 —— Sim-to-Real 的核心技术 # ========================================== import numpy as np class DomainRandomizedEnv: """ 在训练时随机化物理参数,让策略学会应对真实世界的各种变化 """ def __init__(self, base_env): self.env = base_env # 随机化范围 self.randomization_ranges = { "gravity": (-9.5, -10.5), # 重力加速度 "friction": (0.5, 1.5), # 摩擦系数 "mass_scale": (0.8, 1.2), # 物体质量缩放 "joint_damping": (0.8, 1.2), # 关节阻尼 "obs_noise": (0.0, 0.01), # 观测噪声 "action_noise": (0.0, 0.02), # 执行噪声 } def randomize(self): """随机化环境参数""" params = {} for name, (low, high) in self.randomization_ranges.items(): params[name] = np.random.uniform(low, high) # 应用到仿真环境 self.env.model.opt.gravity[2] = params["gravity"] # ... 实际实现需要根据具体仿真器API设置 return params def reset(self): self.randomize() return self.env.reset() def step(self, action): # 添加执行噪声 noisy_action = action + np.random.normal(0, self.randomization_ranges["action_noise"][1]) obs, reward, term, trunc, info = self.env.step(noisy_action) # 添加观测噪声 obs += np.random.normal(0, self.randomization_ranges["obs_noise"][1]) return obs, reward, term, trunc, info # 使用域随机化训练 base_env = gym.make("FetchPickAndPlace-v3") dr_env = DomainRandomizedEnv(base_env) model = PPO("MultiInputPolicy", dr_env, verbose=1) model.learn(total_timesteps=2_000_000) model.save("ppo_domain_randomized")

C.5 具身智能学习资源汇总

阶段资源说明
零基础zero2robot43章免费课程,浏览器内运行
入门EI-Beginner复旦OpenMOSS Lab 6阶段教程
系统学习Xbotics Embodied Guide中文社区:综述→路线→仿真→开源实物
资源大全Awesome Physical AI仿真/RL/IL/VLA/基准/硬件 全收集
学术入门Embodied AI Reading Station156篇论文笔记+11大主题阅读路线
框架LeRobotHuggingFace机器人框架(数据→训练→部署)
仿真MuJoCo + Isaac Lab两大主流仿真平台
书籍The Principles and Practice of Embodied Intelligence (2026.8)系统综述:感知/导航/操作/规划/协作

综合项目实战

项目1:企业智能文档助手(组合 RAG + Agent)

架构: ┌──────────────────────────────────────┐ │ 用户界面 │ │ (Streamlit / Gradio) │ └──────────────┬───────────────────────┘ │ ┌──────────────▼───────────────────────┐ │ Supervisor Agent │ │ (任务分类 → 路由到子Agent) │ └───┬──────────┬──────────┬───────────┘ │ │ │ ┌───▼───┐ ┌───▼───┐ ┌───▼────┐ │ RAG │ │ 搜索 │ │ 分析 │ │ Agent │ │ Agent │ │ Agent │ │(文档 │ │(网络 │ │(数据 │ │ 问答) │ │ 搜索) │ │ 分析) │ └───┬───┘ └───┬───┘ └───┬────┘ │ │ │ ┌───▼──────────▼──────────▼───────────┐ │ 共享工具层 │ │ (向量搜索 / Web搜索 / Python执行) │ └──────────────────────────────────────┘

项目2:自动化工作流 Agent

python
# 综合项目骨架:月度复盘Agent class MonthlyReviewAgent: """自动执行月度复盘:读数据→分析→生成报告→发邮件""" def __init__(self): self.agents = { "data_collector": self._create_data_agent(), "analyzer": self._create_analysis_agent(), "writer": self._create_writer_agent(), "reviewer": self._create_reviewer_agent() } self.supervisor = self._create_supervisor() def run_monthly_review(self, month: str): # 1. 数据收集Agent:从数据库/日志读取 raw_data = self.agents["data_collector"].invoke({ "task": f"收集{month}的业务数据:销售额、用户增长、关键事件" }) # 2. 分析Agent:数据洞察 analysis = self.agents["analyzer"].invoke({ "task": "分析业务数据,找出趋势、异常、亮点和问题", "data": raw_data }) # 3. 写作Agent:生成报告 draft = self.agents["writer"].invoke({ "task": "根据分析结果撰写月度复盘报告", "analysis": analysis }) # 4. 审稿Agent:质量把关 final = self.agents["reviewer"].invoke({ "task": "审核报告质量,修正事实错误", "draft": draft }) # 5. Human-in-the-Loop:最终审批后发送 return final

面试高频考点

RAG 方向

问题考察点准备要点
RAG全链路原理?系统理解文档处理→分块→向量化→检索→重排序→生成,每个环节的优化点
如何提升召回率?优化能力混合检索、查询改写、HyDE、Rerank、多路召回融合
如何处理多轮对话中的RAG?工程经验查询改写融合历史、滑动窗口、对话状态管理
向量数据库选型?架构决策Milvus(生产) vs Chroma(原型) vs FAISS(轻量) vs Qdrant(过滤强)
RAG评估怎么做?质量保障Ragas指标、人工评估、A/B测试、回归测试

Agent 方向

问题考察点准备要点
ReAct模式原理?核心机制推理+行动的交替循环,与传统链式调用的区别
如何防止Agent死循环?工程能力max_iterations、收敛检测、Human-in-the-Loop
Multi-Agent架构设计?系统设计Supervisor、Swarm、层次化、何时用哪种模式
Agent如何保证安全性?安全意识工具权限最小化、提示注入防护、人工审批关键操作
MCP协议是什么?前沿技术AI的USB接口、Tools/Resources/Prompts三大能力、传输方式

学习检查清单

方向A(RAG + 微调)

  • 跑通 OpenAI API 对话和流式输出
  • 掌握 Zero-shot / Few-shot / CoT / ReAct 四种提示模式
  • 实现完整的 RAG 系统(文档加载→分块→向量化→检索→生成)
  • 实现混合检索 + Rerank 优化
  • 使用 Ragas 完成 RAG 质量评估
  • 使用 QLoRA 完成一次模型微调
  • 部署一套 RAG 系统作为 REST API

方向B(AI Agent)

  • 实现 Function Calling Agent(3+工具)
  • 使用 LangGraph 实现 ReAct Agent 循环
  • 实现 Human-in-the-Loop 审批流程
  • 实现 Multi-Agent Supervisor 模式
  • 开发并部署一个 MCP Server
  • 将 Agent 部署为 Docker 服务
  • 完成一个完整的多Agent项目(如月度复盘Agent)

方向C(具身智能)

  • 安装 MuJoCo / PyBullet 并运行首个仿真
  • 完成 EI-Beginner 的 6 个任务
  • 实现行为克隆(BC)策略
  • 实现 PPO 训练机械臂
  • 了解 Sim-to-Real 域随机化
  • 运行 OpenVLA 或 π0 模型推理
  • 完成一个完整的仿真→训练→部署 demo

最后的话:2026年是Agent元年。建议优先深耕方向A+B(RAG + Agent),这两项技能组合是当前市场需求最大、薪资溢价最高、且纯软件方向最适合软件工程师转型的路径。方向C(具身智能)需要硬件/仿真背景,适合有机电/机器人基础的同学。记住:项目作品 > 证书,原理理解 > API调用,工程能力 > Demo能力。

本文作者:张京

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!