[{"data":1,"prerenderedAt":2818},["ShallowReactive",2],{"article-/articles/agent-intro":3},{"id":4,"title":5,"author":6,"body":7,"category":2804,"date":2805,"description":2806,"extension":2807,"featured":2808,"home_position":2809,"image":2810,"meta":2811,"navigation":179,"order":130,"path":2812,"seo":2813,"status":2809,"stem":2814,"tags":2815,"__hash__":2817},"content/articles/agent-intro.md","Agent入门","sibuchen",{"type":8,"value":9,"toc":2775},"minimark",[10,14,25,31,36,90,95,102,114,119,122,128,134,163,227,232,330,334,339,362,367,672,677,749,752,757,761,853,857,861,866,871,1876,1878,1883,1887,1999,2003,2009,2013,2018,2024,2028,2032,2105,2109,2115,2119,2125,2129,2135,2139,2143,2210,2214,2216,2221,2226,2231,2236,2239,2245,2250,2254,2259,2265,2268,2274,2277,2280,2285,2290,2295,2412,2415,2466,2469,2474,2480,2483,2488,2493,2499,2502,2507,2512,2518,2521,2526,2532,2535,2540,2546,2549,2555,2560,2566,2570,2576,2580,2585,2590,2596,2600,2611,2702,2706,2710,2729,2733,2748,2752,2761,2765,2771],[11,12,13],"p",{},"教程大纲：",[15,16,21],"pre",{"className":17,"code":19,"language":20},[18],"language-text","1. agent llm workflow概念区别 + agent的技术介绍\n2. 国内大龙虾 的使用教程（下载 连接大模型 配置skills MCPs multi-agent配置与使用）\n3. ClaudeCode 的使用教程（下载 配置大模型 下载并使用 “CLI + skills”的组合）\n","text",[22,23,19],"code",{"__ignoreMap":24},"",[11,26,27],{},[28,29],"img",{"alt":24,"src":30},"/assets/agent-intro/%E6%95%99%E7%A8%8B%E5%A4%A7%E7%BA%B2.png",[32,33,35],"h2",{"id":34},"_1-概念区分","1. 概念区分",[37,38,39,58],"table",{},[40,41,42],"thead",{},[43,44,45,49,52,55],"tr",{},[46,47,48],"th",{},"维度",[46,50,51],{},"LLM",[46,53,54],{},"WorkFlow",[46,56,57],{},"Agent",[59,60,61,76],"tbody",{},[43,62,63,67,70,73],{},[64,65,66],"td",{},"本质",[64,68,69],{},"一组训练出来的权重文件（数十亿个参数），运行时这些参数驱动 Transformer 网络进行概率预测",[64,71,72],{},"一套预先定义好的执行流程（状态机/流程图）",[64,74,75],{},"LLM + 工具 + 记忆 + 规划机制组成的自主执行系统",[43,77,78,81,84,87],{},[64,79,80],{},"核心",[64,82,83],{},"输入 Prompt -> 生成答案",[64,85,86],{},"开发者提前定义流程，LLM按照流程执行",[64,88,89],{},"LLM自主决定下一步行动",[91,92,94],"h3",{"id":93},"_11-快速体验-llm","1.1. 快速体验 LLM",[96,97,98],"ol",{},[99,100,101],"li",{},"选择模型 并 下载权重文件",[103,104,105],"blockquote",{},[11,106,107],{},[108,109,113],"a",{"href":110,"rel":111},"https://huggingface.co/",[112],"nofollow","HuggingFace",[11,115,116],{},[28,117],{"alt":24,"src":118},"/assets/agent-intro/llm_google_gemma-4-12B-it.png",[11,120,121],{},"预期结构：",[15,123,126],{"className":124,"code":125,"language":20},[18],"gemma/\n├── config.json\n├── tokenizer.json\n├── generation_config.json\n├── model.safetensors\n└── ...\n",[22,127,125],{"__ignoreMap":24},[96,129,131],{"start":130},2,[99,132,133],{},"安装依赖 并 加载模型",[15,135,139],{"className":136,"code":137,"language":138,"meta":24,"style":24},"language-bash shiki shiki-themes github-light github-dark","pip install transformers torch accelerate\n","bash",[22,140,141],{"__ignoreMap":24},[142,143,146,150,154,157,160],"span",{"class":144,"line":145},"line",1,[142,147,149],{"class":148},"sScJk","pip",[142,151,153],{"class":152},"sZZnC"," install",[142,155,156],{"class":152}," transformers",[142,158,159],{"class":152}," torch",[142,161,162],{"class":152}," accelerate\n",[15,164,168],{"className":165,"code":166,"language":167,"meta":24,"style":24},"language-python shiki shiki-themes github-light github-dark","from transformers import AutoTokenizer, AutoModelForCausalLM\n\nmodel_path = \"./gemma\"\n\ntokenizer = AutoTokenizer.from_pretrained(model_path)\n\nmodel = AutoModelForCausalLM.from_pretrained(\n    model_path,\n    device_map=\"auto\"\n)\n","python",[22,169,170,175,181,187,192,198,203,209,215,221],{"__ignoreMap":24},[142,171,172],{"class":144,"line":145},[142,173,174],{},"from transformers import AutoTokenizer, AutoModelForCausalLM\n",[142,176,177],{"class":144,"line":130},[142,178,180],{"emptyLinePlaceholder":179},true,"\n",[142,182,184],{"class":144,"line":183},3,[142,185,186],{},"model_path = \"./gemma\"\n",[142,188,190],{"class":144,"line":189},4,[142,191,180],{"emptyLinePlaceholder":179},[142,193,195],{"class":144,"line":194},5,[142,196,197],{},"tokenizer = AutoTokenizer.from_pretrained(model_path)\n",[142,199,201],{"class":144,"line":200},6,[142,202,180],{"emptyLinePlaceholder":179},[142,204,206],{"class":144,"line":205},7,[142,207,208],{},"model = AutoModelForCausalLM.from_pretrained(\n",[142,210,212],{"class":144,"line":211},8,[142,213,214],{},"    model_path,\n",[142,216,218],{"class":144,"line":217},9,[142,219,220],{},"    device_map=\"auto\"\n",[142,222,224],{"class":144,"line":223},10,[142,225,226],{},")\n",[96,228,229],{"start":183},[99,230,231],{},"have a try",[15,233,235],{"className":165,"code":234,"language":167,"meta":24,"style":24},"prompt = \"广东财经大学的校史？\"\n\ninputs = tokenizer(\n    prompt,\n    return_tensors=\"pt\"\n).to(model.device)\n\noutputs = model.generate(\n    **inputs,\n    max_new_tokens=50\n)\n\nprint(\n    tokenizer.decode(\n        outputs[0],\n        skip_special_tokens=True\n    )\n)\n",[22,236,237,242,246,251,256,261,266,270,275,280,285,290,295,301,307,313,319,325],{"__ignoreMap":24},[142,238,239],{"class":144,"line":145},[142,240,241],{},"prompt = \"广东财经大学的校史？\"\n",[142,243,244],{"class":144,"line":130},[142,245,180],{"emptyLinePlaceholder":179},[142,247,248],{"class":144,"line":183},[142,249,250],{},"inputs = tokenizer(\n",[142,252,253],{"class":144,"line":189},[142,254,255],{},"    prompt,\n",[142,257,258],{"class":144,"line":194},[142,259,260],{},"    return_tensors=\"pt\"\n",[142,262,263],{"class":144,"line":200},[142,264,265],{},").to(model.device)\n",[142,267,268],{"class":144,"line":205},[142,269,180],{"emptyLinePlaceholder":179},[142,271,272],{"class":144,"line":211},[142,273,274],{},"outputs = model.generate(\n",[142,276,277],{"class":144,"line":217},[142,278,279],{},"    **inputs,\n",[142,281,282],{"class":144,"line":223},[142,283,284],{},"    max_new_tokens=50\n",[142,286,288],{"class":144,"line":287},11,[142,289,226],{},[142,291,293],{"class":144,"line":292},12,[142,294,180],{"emptyLinePlaceholder":179},[142,296,298],{"class":144,"line":297},13,[142,299,300],{},"print(\n",[142,302,304],{"class":144,"line":303},14,[142,305,306],{},"    tokenizer.decode(\n",[142,308,310],{"class":144,"line":309},15,[142,311,312],{},"        outputs[0],\n",[142,314,316],{"class":144,"line":315},16,[142,317,318],{},"        skip_special_tokens=True\n",[142,320,322],{"class":144,"line":321},17,[142,323,324],{},"    )\n",[142,326,328],{"class":144,"line":327},18,[142,329,226],{},[91,331,333],{"id":332},"_12-快速体验-workflow","1.2. 快速体验 WorkFlow",[96,335,336],{},[99,337,338],{},"安装依赖",[15,340,342],{"className":136,"code":341,"language":138,"meta":24,"style":24},"pip install langgraph langchain langchain-openai python-dotenv\n",[22,343,344],{"__ignoreMap":24},[142,345,346,348,350,353,356,359],{"class":144,"line":145},[142,347,149],{"class":148},[142,349,153],{"class":152},[142,351,352],{"class":152}," langgraph",[142,354,355],{"class":152}," langchain",[142,357,358],{"class":152}," langchain-openai",[142,360,361],{"class":152}," python-dotenv\n",[96,363,364],{"start":130},[99,365,366],{},"定义节点",[15,368,370],{"className":165,"code":369,"language":167,"meta":24,"style":24},"from langchain_core.prompts import ChatPromptTemplate\nfrom langchain_openai import ChatOpenAI\nfrom langgraph.graph import StateGraph, START, END\nfrom typing import TypedDict, Optional\nimport os\nfrom dotenv import load_dotenv\n\n# ========== 1. 初始化 LLM ==========\nload_dotenv()\n\nllm = ChatOpenAI(\n    api_key=os.getenv(\"API_KEY\"),\n    base_url=\"https://api.deepseek.com\",\n    model=\"deepseek-v4-pro\",\n    temperature=0.2\n)\n\n# ========== 2. 状态定义 ==========\nclass ChainState(TypedDict):\n    task: str\n    draft: Optional[str]\n    corrected: Optional[str]\n    polished: Optional[str]\n\n# ========== 3. Agent Prompt ==========\nwrite_agent = ChatPromptTemplate.from_messages([\n    (\"system\", \"你是写作智能体，只负责生成初稿，不要解释。\"),\n    (\"user\", \"{task}\")\n]) | llm\n\ncorrect_agent = ChatPromptTemplate.from_messages([\n    (\"system\", \"你是纠错智能体，只修正语法、逻辑和错别字，不扩写。\"),\n    (\"user\", \"{draft}\")\n]) | llm\n\npolish_agent = ChatPromptTemplate.from_messages([\n    (\"system\", \"你是润色智能体，只提升表达质量和专业度，不改变意思。\"),\n    (\"user\", \"{corrected}\")\n]) | llm\n\n# ========== 4. Agent Node ==========\ndef writer_node(state: ChainState):\n    print(\"\\n✍️【Writer Agent】生成初稿中...\")\n    res = write_agent.invoke({\"task\": state[\"task\"]})\n    return {\"draft\": res.content.strip()}\n\ndef correct_node(state: ChainState):\n    print(\"\\n🧹【Corrector Agent】纠错中...\")\n    res = correct_agent.invoke({\"draft\": state[\"draft\"]})\n    return {\"corrected\": res.content.strip()}\n\ndef polish_node(state: ChainState):\n    print(\"\\n✨【Polisher Agent】润色中...\")\n    res = polish_agent.invoke({\"corrected\": state[\"corrected\"]})\n    return {\"polished\": res.content.strip()}\n",[22,371,372,377,382,387,392,397,402,406,411,416,420,425,430,435,440,445,449,453,458,464,470,476,482,488,493,499,505,511,517,523,528,534,540,546,551,556,562,568,574,579,584,590,596,602,608,614,619,625,631,637,643,648,654,660,666],{"__ignoreMap":24},[142,373,374],{"class":144,"line":145},[142,375,376],{},"from langchain_core.prompts import ChatPromptTemplate\n",[142,378,379],{"class":144,"line":130},[142,380,381],{},"from langchain_openai import ChatOpenAI\n",[142,383,384],{"class":144,"line":183},[142,385,386],{},"from langgraph.graph import StateGraph, START, END\n",[142,388,389],{"class":144,"line":189},[142,390,391],{},"from typing import TypedDict, Optional\n",[142,393,394],{"class":144,"line":194},[142,395,396],{},"import os\n",[142,398,399],{"class":144,"line":200},[142,400,401],{},"from dotenv import load_dotenv\n",[142,403,404],{"class":144,"line":205},[142,405,180],{"emptyLinePlaceholder":179},[142,407,408],{"class":144,"line":211},[142,409,410],{},"# ========== 1. 初始化 LLM ==========\n",[142,412,413],{"class":144,"line":217},[142,414,415],{},"load_dotenv()\n",[142,417,418],{"class":144,"line":223},[142,419,180],{"emptyLinePlaceholder":179},[142,421,422],{"class":144,"line":287},[142,423,424],{},"llm = ChatOpenAI(\n",[142,426,427],{"class":144,"line":292},[142,428,429],{},"    api_key=os.getenv(\"API_KEY\"),\n",[142,431,432],{"class":144,"line":297},[142,433,434],{},"    base_url=\"https://api.deepseek.com\",\n",[142,436,437],{"class":144,"line":303},[142,438,439],{},"    model=\"deepseek-v4-pro\",\n",[142,441,442],{"class":144,"line":309},[142,443,444],{},"    temperature=0.2\n",[142,446,447],{"class":144,"line":315},[142,448,226],{},[142,450,451],{"class":144,"line":321},[142,452,180],{"emptyLinePlaceholder":179},[142,454,455],{"class":144,"line":327},[142,456,457],{},"# ========== 2. 状态定义 ==========\n",[142,459,461],{"class":144,"line":460},19,[142,462,463],{},"class ChainState(TypedDict):\n",[142,465,467],{"class":144,"line":466},20,[142,468,469],{},"    task: str\n",[142,471,473],{"class":144,"line":472},21,[142,474,475],{},"    draft: Optional[str]\n",[142,477,479],{"class":144,"line":478},22,[142,480,481],{},"    corrected: Optional[str]\n",[142,483,485],{"class":144,"line":484},23,[142,486,487],{},"    polished: Optional[str]\n",[142,489,491],{"class":144,"line":490},24,[142,492,180],{"emptyLinePlaceholder":179},[142,494,496],{"class":144,"line":495},25,[142,497,498],{},"# ========== 3. Agent Prompt ==========\n",[142,500,502],{"class":144,"line":501},26,[142,503,504],{},"write_agent = ChatPromptTemplate.from_messages([\n",[142,506,508],{"class":144,"line":507},27,[142,509,510],{},"    (\"system\", \"你是写作智能体，只负责生成初稿，不要解释。\"),\n",[142,512,514],{"class":144,"line":513},28,[142,515,516],{},"    (\"user\", \"{task}\")\n",[142,518,520],{"class":144,"line":519},29,[142,521,522],{},"]) | llm\n",[142,524,526],{"class":144,"line":525},30,[142,527,180],{"emptyLinePlaceholder":179},[142,529,531],{"class":144,"line":530},31,[142,532,533],{},"correct_agent = ChatPromptTemplate.from_messages([\n",[142,535,537],{"class":144,"line":536},32,[142,538,539],{},"    (\"system\", \"你是纠错智能体，只修正语法、逻辑和错别字，不扩写。\"),\n",[142,541,543],{"class":144,"line":542},33,[142,544,545],{},"    (\"user\", \"{draft}\")\n",[142,547,549],{"class":144,"line":548},34,[142,550,522],{},[142,552,554],{"class":144,"line":553},35,[142,555,180],{"emptyLinePlaceholder":179},[142,557,559],{"class":144,"line":558},36,[142,560,561],{},"polish_agent = ChatPromptTemplate.from_messages([\n",[142,563,565],{"class":144,"line":564},37,[142,566,567],{},"    (\"system\", \"你是润色智能体，只提升表达质量和专业度，不改变意思。\"),\n",[142,569,571],{"class":144,"line":570},38,[142,572,573],{},"    (\"user\", \"{corrected}\")\n",[142,575,577],{"class":144,"line":576},39,[142,578,522],{},[142,580,582],{"class":144,"line":581},40,[142,583,180],{"emptyLinePlaceholder":179},[142,585,587],{"class":144,"line":586},41,[142,588,589],{},"# ========== 4. Agent Node ==========\n",[142,591,593],{"class":144,"line":592},42,[142,594,595],{},"def writer_node(state: ChainState):\n",[142,597,599],{"class":144,"line":598},43,[142,600,601],{},"    print(\"\\n✍️【Writer Agent】生成初稿中...\")\n",[142,603,605],{"class":144,"line":604},44,[142,606,607],{},"    res = write_agent.invoke({\"task\": state[\"task\"]})\n",[142,609,611],{"class":144,"line":610},45,[142,612,613],{},"    return {\"draft\": res.content.strip()}\n",[142,615,617],{"class":144,"line":616},46,[142,618,180],{"emptyLinePlaceholder":179},[142,620,622],{"class":144,"line":621},47,[142,623,624],{},"def correct_node(state: ChainState):\n",[142,626,628],{"class":144,"line":627},48,[142,629,630],{},"    print(\"\\n🧹【Corrector Agent】纠错中...\")\n",[142,632,634],{"class":144,"line":633},49,[142,635,636],{},"    res = correct_agent.invoke({\"draft\": state[\"draft\"]})\n",[142,638,640],{"class":144,"line":639},50,[142,641,642],{},"    return {\"corrected\": res.content.strip()}\n",[142,644,646],{"class":144,"line":645},51,[142,647,180],{"emptyLinePlaceholder":179},[142,649,651],{"class":144,"line":650},52,[142,652,653],{},"def polish_node(state: ChainState):\n",[142,655,657],{"class":144,"line":656},53,[142,658,659],{},"    print(\"\\n✨【Polisher Agent】润色中...\")\n",[142,661,663],{"class":144,"line":662},54,[142,664,665],{},"    res = polish_agent.invoke({\"corrected\": state[\"corrected\"]})\n",[142,667,669],{"class":144,"line":668},55,[142,670,671],{},"    return {\"polished\": res.content.strip()}\n",[96,673,674],{"start":183},[99,675,676],{},"构建工作流",[15,678,680],{"className":165,"code":679,"language":167,"meta":24,"style":24},"# ========== 5. 构建链式 LangGraph ==========\nworkflow = StateGraph(ChainState)\n\nworkflow.add_node(\"writer\", writer_node)\nworkflow.add_node(\"corrector\", correct_node)\nworkflow.add_node(\"polisher\", polish_node)\n\n# 链式 Pipeline\nworkflow.add_edge(START, \"writer\")\nworkflow.add_edge(\"writer\", \"corrector\")\nworkflow.add_edge(\"corrector\", \"polisher\")\nworkflow.add_edge(\"polisher\", END)\n\napp = workflow.compile()\n\n",[22,681,682,687,692,696,701,706,711,715,720,725,730,735,740,744],{"__ignoreMap":24},[142,683,684],{"class":144,"line":145},[142,685,686],{},"# ========== 5. 构建链式 LangGraph ==========\n",[142,688,689],{"class":144,"line":130},[142,690,691],{},"workflow = StateGraph(ChainState)\n",[142,693,694],{"class":144,"line":183},[142,695,180],{"emptyLinePlaceholder":179},[142,697,698],{"class":144,"line":189},[142,699,700],{},"workflow.add_node(\"writer\", writer_node)\n",[142,702,703],{"class":144,"line":194},[142,704,705],{},"workflow.add_node(\"corrector\", correct_node)\n",[142,707,708],{"class":144,"line":200},[142,709,710],{},"workflow.add_node(\"polisher\", polish_node)\n",[142,712,713],{"class":144,"line":205},[142,714,180],{"emptyLinePlaceholder":179},[142,716,717],{"class":144,"line":211},[142,718,719],{},"# 链式 Pipeline\n",[142,721,722],{"class":144,"line":217},[142,723,724],{},"workflow.add_edge(START, \"writer\")\n",[142,726,727],{"class":144,"line":223},[142,728,729],{},"workflow.add_edge(\"writer\", \"corrector\")\n",[142,731,732],{"class":144,"line":287},[142,733,734],{},"workflow.add_edge(\"corrector\", \"polisher\")\n",[142,736,737],{"class":144,"line":292},[142,738,739],{},"workflow.add_edge(\"polisher\", END)\n",[142,741,742],{"class":144,"line":297},[142,743,180],{"emptyLinePlaceholder":179},[142,745,746],{"class":144,"line":303},[142,747,748],{},"app = workflow.compile()\n",[11,750,751],{},"流程图：",[11,753,754],{},[28,755],{"alt":24,"src":756},"/assets/agent-intro/workflow.png",[96,758,759],{"start":189},[99,760,231],{},[15,762,764],{"className":165,"code":763,"language":167,"meta":24,"style":24},"# ========== 6. 运行 ==========\nif __name__ == \"__main__\":\n    init_state = {\n        \"task\": \"撰写一篇150字左右的介绍文，说明LangGraph多智能体的核心优势，适合技术初学者阅读\",\n        \"draft\": None,\n        \"corrected\": None,\n        \"polished\": None,\n    }\n\n    result = app.invoke(init_state)\n\n    print(\"\\n\" + \"=\" * 90)\n    print(\"📊 链式多智能体 Pipeline 最终结果\")\n    print(\"=\" * 90)\n    print(\"\\n📝 初稿：\\n\", result[\"draft\"])\n    print(\"\\n✅ 纠错：\\n\", result[\"corrected\"])\n    print(\"\\n✨ 润色：\\n\", result[\"polished\"])\n    print(\"=\" * 90)\n",[22,765,766,771,776,781,786,791,796,801,806,810,815,819,824,829,834,839,844,849],{"__ignoreMap":24},[142,767,768],{"class":144,"line":145},[142,769,770],{},"# ========== 6. 运行 ==========\n",[142,772,773],{"class":144,"line":130},[142,774,775],{},"if __name__ == \"__main__\":\n",[142,777,778],{"class":144,"line":183},[142,779,780],{},"    init_state = {\n",[142,782,783],{"class":144,"line":189},[142,784,785],{},"        \"task\": \"撰写一篇150字左右的介绍文，说明LangGraph多智能体的核心优势，适合技术初学者阅读\",\n",[142,787,788],{"class":144,"line":194},[142,789,790],{},"        \"draft\": None,\n",[142,792,793],{"class":144,"line":200},[142,794,795],{},"        \"corrected\": None,\n",[142,797,798],{"class":144,"line":205},[142,799,800],{},"        \"polished\": None,\n",[142,802,803],{"class":144,"line":211},[142,804,805],{},"    }\n",[142,807,808],{"class":144,"line":217},[142,809,180],{"emptyLinePlaceholder":179},[142,811,812],{"class":144,"line":223},[142,813,814],{},"    result = app.invoke(init_state)\n",[142,816,817],{"class":144,"line":287},[142,818,180],{"emptyLinePlaceholder":179},[142,820,821],{"class":144,"line":292},[142,822,823],{},"    print(\"\\n\" + \"=\" * 90)\n",[142,825,826],{"class":144,"line":297},[142,827,828],{},"    print(\"📊 链式多智能体 Pipeline 最终结果\")\n",[142,830,831],{"class":144,"line":303},[142,832,833],{},"    print(\"=\" * 90)\n",[142,835,836],{"class":144,"line":309},[142,837,838],{},"    print(\"\\n📝 初稿：\\n\", result[\"draft\"])\n",[142,840,841],{"class":144,"line":315},[142,842,843],{},"    print(\"\\n✅ 纠错：\\n\", result[\"corrected\"])\n",[142,845,846],{"class":144,"line":321},[142,847,848],{},"    print(\"\\n✨ 润色：\\n\", result[\"polished\"])\n",[142,850,851],{"class":144,"line":327},[142,852,833],{},[91,854,856],{"id":855},"_13-快速体验-agent","1.3. 快速体验 Agent",[96,858,859],{},[99,860,338],{},[15,862,864],{"className":863,"code":341,"language":20},[18],[22,865,341],{"__ignoreMap":24},[96,867,868],{"start":130},[99,869,870],{},"定义 智能体",[15,872,874],{"className":165,"code":873,"language":167,"meta":24,"style":24},"from typing import TypedDict, Optional\nfrom langgraph.graph import StateGraph, START, END\nfrom langchain_openai import ChatOpenAI\nfrom langchain_core.prompts import ChatPromptTemplate\nimport os\nfrom dotenv import load_dotenv\n\n# ================== 初始化环境 ==================\nload_dotenv()\nllm = ChatOpenAI(\n    api_key=os.getenv(\"API_KEY\"),\n    base_url=\"https://api.deepseek.com\",\n    model=\"deepseek-chat\",\n    temperature=0.3\n)\n\n# ================== 状态定义 ==================\nclass TaskState(TypedDict):\n    task: str\n    research: Optional[str]\n    draft: Optional[str]\n    code: Optional[str]\n    math: Optional[str]\n    next_agent: Optional[str]\n    result: Optional[str]\n    round_count: int  # Supervisor 执行轮次\n    supervisor_thoughts: Optional[str]  # 打印 LLM 思考过程\n\nMAX_ROUNDS = 3\n\n# ================== sub-agent ==================\nresearch_agent = ChatPromptTemplate.from_messages([\n    (\"user\", \"请调研以下任务的背景信息，整理成条列要点，中文输出：{task}\")\n]) | llm\n\nwriter_agent = ChatPromptTemplate.from_messages([\n    (\"user\", \"根据以下信息撰写中文技术文章或说明文：{research}\")\n]) | llm\n\ncode_agent = ChatPromptTemplate.from_messages([\n    (\"user\", \"请根据以下任务生成 Python 示例代码：{task}\")\n]) | llm\n\nmath_agent = ChatPromptTemplate.from_messages([\n    (\"user\", \"请解决以下数学/逻辑问题，并详细说明过程：{task}\")\n]) | llm\n\n# ================== 动态 Supervisor 节点 ==================\ndef supervisor_node(state: TaskState):\n    new_round = state[\"round_count\"] + 1\n\n    # 超过最大轮次，触发兜底\n    if new_round > MAX_ROUNDS:\n        print(f\"⚠️ 超过最大轮次 {MAX_ROUNDS}，触发兜底 → 结束任务\")\n        return {\n            \"round_count\": new_round,\n            \"next_agent\": \"end\",\n            \"supervisor_thoughts\": \"轮次数超过上限，直接结束任务\"\n        }\n\n    # 中文提示词，严格约束 LLM\n    prompt = f\"\"\"\n你是多智能体系统的主管智能体（Supervisor），负责调度专家智能体，但你不执行任务。请阅读当前任务和已完成状态，并选择下一步最合适的智能体执行。\n\n任务：\n{state['task']}\n\n已完成状态：\n- 调研: {\"已完成\" if state.get(\"research\") else \"未完成\"}\n- 写作: {\"已完成\" if state.get(\"draft\") else \"未完成\"}\n- 编程: {\"已完成\" if state.get(\"code\") else \"未完成\"}\n- 数学: {\"已完成\" if state.get(\"math\") else \"未完成\"}\n\n可调度智能体：\n- research_agent：负责调研和整理资料\n- writer_agent：负责撰写中文文章或说明文\n- code_agent：负责编写 Python 代码\n- math_agent：负责数学/逻辑计算与推理\n\n约束：\n1. 不能选择已完成的智能体。\n2. 必须选择与任务相关的智能体。\n3. 如果所有任务完成，返回 \"end\"。\n4. 请在回答中先写出你的“思考过程”，然后在最后一行返回下一步智能体名称（research_agent / writer_agent / code_agent / math_agent / end）。\n\n请用中文完整回答：\n\"\"\"\n\n    res = llm.invoke(prompt)\n    thoughts = res.content.strip()\n    last_line = thoughts.splitlines()[-1]\n    valid_agents = (\"research_agent\", \"writer_agent\", \"code_agent\", \"math_agent\", \"end\")\n    next_agent = next((a for a in valid_agents if a in last_line), \"end\")\n    print(f\"🧠 主管思考过程：\\n{thoughts}\\n\")\n    print(f\"🧠 主管调度 → {next_agent} (轮次 {new_round})\")\n    \n    return {\n        \"round_count\": new_round,\n        \"next_agent\": next_agent,\n        \"supervisor_thoughts\": thoughts\n    }\n\n# ================== 员工节点 ==================\ndef research_node(state: TaskState):\n    print(\">>> Research Agent 执行中...\")\n    try:\n        res = research_agent.invoke({\"task\": state[\"task\"]})\n        result = res.content.strip()\n    except Exception as e:\n        result = f\"调研失败：{str(e)[:50]}\"\n    \n    # ✅ 正确写法：只返回更新字段\n    return {\n        \"research\": result,\n        \"result\": result\n    }\n\ndef writer_node(state: TaskState):\n    print(\">>> Writer Agent 执行中...\")\n    try:\n        res = writer_agent.invoke({\"research\": state.get(\"research\",\"\")})\n        result = res.content.strip()\n    except Exception as e:\n        result = f\"写作失败：{str(e)[:50]}\"\n    \n    # ✅ 正确写法\n    return {\n        \"draft\": result,\n        \"result\": result\n    }\n\ndef code_node(state: TaskState):\n    print(\">>> Code Agent 执行中...\")\n    try:\n        res = code_agent.invoke({\"task\": state[\"task\"]})\n        result = res.content.strip()\n    except Exception as e:\n        result = f\"代码生成失败：{str(e)[:50]}\"\n    \n    # ✅ 正确写法\n    return {\n        \"code\": result,\n        \"result\": result\n    }\n\ndef math_node(state: TaskState):\n    print(\">>> Math Agent 执行中...\")\n    try:\n        res = math_agent.invoke({\"task\": state[\"task\"]})\n        result = res.content.strip()\n    except Exception as e:\n        result = f\"数学求解失败：{str(e)[:50]}\"\n    \n    # ✅ 正确写法\n    return {\n        \"math\": result,\n        \"result\": result\n    }\n\n# ================== 构建 LangGraph ==================\nworkflow = StateGraph(TaskState)\n\nworkflow.add_node(\"supervisor\", supervisor_node)\nworkflow.add_node(\"research_agent\", research_node)\nworkflow.add_node(\"writer_agent\", writer_node)\nworkflow.add_node(\"code_agent\", code_node)\nworkflow.add_node(\"math_agent\", math_node)\n\nworkflow.add_edge(START, \"supervisor\")\n\nworkflow.add_conditional_edges(\n    \"supervisor\",\n    lambda s: s[\"next_agent\"],\n    {\n        \"research_agent\": \"research_agent\",\n        \"writer_agent\": \"writer_agent\",\n        \"code_agent\": \"code_agent\",\n        \"math_agent\": \"math_agent\",\n        \"end\": END\n    }\n)\n\nworkflow.add_edge(\"research_agent\", \"supervisor\")\nworkflow.add_edge(\"writer_agent\", \"supervisor\")\nworkflow.add_edge(\"code_agent\", \"supervisor\")\nworkflow.add_edge(\"math_agent\", \"supervisor\")\n\napp = workflow.compile()\n",[22,875,876,880,884,888,892,896,900,904,909,913,917,921,925,930,935,939,943,948,953,957,962,966,971,976,981,986,991,996,1000,1005,1009,1014,1019,1024,1028,1032,1037,1042,1046,1050,1055,1060,1064,1068,1073,1078,1082,1086,1091,1096,1101,1105,1110,1115,1120,1125,1131,1137,1143,1149,1154,1160,1166,1172,1177,1183,1189,1194,1200,1206,1212,1218,1224,1229,1235,1241,1247,1253,1259,1264,1270,1276,1282,1288,1294,1299,1305,1311,1316,1322,1328,1334,1340,1346,1352,1358,1364,1370,1376,1382,1388,1393,1398,1404,1410,1416,1422,1428,1434,1440,1446,1451,1457,1462,1468,1474,1479,1484,1490,1496,1501,1507,1512,1517,1523,1528,1534,1539,1545,1550,1555,1560,1566,1572,1577,1583,1588,1593,1599,1604,1609,1614,1620,1625,1630,1635,1641,1647,1652,1658,1663,1668,1674,1679,1684,1689,1695,1700,1705,1710,1716,1722,1727,1733,1739,1745,1751,1757,1762,1768,1773,1779,1785,1791,1797,1803,1809,1815,1821,1827,1832,1837,1842,1848,1854,1860,1866,1871],{"__ignoreMap":24},[142,877,878],{"class":144,"line":145},[142,879,391],{},[142,881,882],{"class":144,"line":130},[142,883,386],{},[142,885,886],{"class":144,"line":183},[142,887,381],{},[142,889,890],{"class":144,"line":189},[142,891,376],{},[142,893,894],{"class":144,"line":194},[142,895,396],{},[142,897,898],{"class":144,"line":200},[142,899,401],{},[142,901,902],{"class":144,"line":205},[142,903,180],{"emptyLinePlaceholder":179},[142,905,906],{"class":144,"line":211},[142,907,908],{},"# ================== 初始化环境 ==================\n",[142,910,911],{"class":144,"line":217},[142,912,415],{},[142,914,915],{"class":144,"line":223},[142,916,424],{},[142,918,919],{"class":144,"line":287},[142,920,429],{},[142,922,923],{"class":144,"line":292},[142,924,434],{},[142,926,927],{"class":144,"line":297},[142,928,929],{},"    model=\"deepseek-chat\",\n",[142,931,932],{"class":144,"line":303},[142,933,934],{},"    temperature=0.3\n",[142,936,937],{"class":144,"line":309},[142,938,226],{},[142,940,941],{"class":144,"line":315},[142,942,180],{"emptyLinePlaceholder":179},[142,944,945],{"class":144,"line":321},[142,946,947],{},"# ================== 状态定义 ==================\n",[142,949,950],{"class":144,"line":327},[142,951,952],{},"class TaskState(TypedDict):\n",[142,954,955],{"class":144,"line":460},[142,956,469],{},[142,958,959],{"class":144,"line":466},[142,960,961],{},"    research: Optional[str]\n",[142,963,964],{"class":144,"line":472},[142,965,475],{},[142,967,968],{"class":144,"line":478},[142,969,970],{},"    code: Optional[str]\n",[142,972,973],{"class":144,"line":484},[142,974,975],{},"    math: Optional[str]\n",[142,977,978],{"class":144,"line":490},[142,979,980],{},"    next_agent: Optional[str]\n",[142,982,983],{"class":144,"line":495},[142,984,985],{},"    result: Optional[str]\n",[142,987,988],{"class":144,"line":501},[142,989,990],{},"    round_count: int  # Supervisor 执行轮次\n",[142,992,993],{"class":144,"line":507},[142,994,995],{},"    supervisor_thoughts: Optional[str]  # 打印 LLM 思考过程\n",[142,997,998],{"class":144,"line":513},[142,999,180],{"emptyLinePlaceholder":179},[142,1001,1002],{"class":144,"line":519},[142,1003,1004],{},"MAX_ROUNDS = 3\n",[142,1006,1007],{"class":144,"line":525},[142,1008,180],{"emptyLinePlaceholder":179},[142,1010,1011],{"class":144,"line":530},[142,1012,1013],{},"# ================== sub-agent ==================\n",[142,1015,1016],{"class":144,"line":536},[142,1017,1018],{},"research_agent = ChatPromptTemplate.from_messages([\n",[142,1020,1021],{"class":144,"line":542},[142,1022,1023],{},"    (\"user\", \"请调研以下任务的背景信息，整理成条列要点，中文输出：{task}\")\n",[142,1025,1026],{"class":144,"line":548},[142,1027,522],{},[142,1029,1030],{"class":144,"line":553},[142,1031,180],{"emptyLinePlaceholder":179},[142,1033,1034],{"class":144,"line":558},[142,1035,1036],{},"writer_agent = ChatPromptTemplate.from_messages([\n",[142,1038,1039],{"class":144,"line":564},[142,1040,1041],{},"    (\"user\", \"根据以下信息撰写中文技术文章或说明文：{research}\")\n",[142,1043,1044],{"class":144,"line":570},[142,1045,522],{},[142,1047,1048],{"class":144,"line":576},[142,1049,180],{"emptyLinePlaceholder":179},[142,1051,1052],{"class":144,"line":581},[142,1053,1054],{},"code_agent = ChatPromptTemplate.from_messages([\n",[142,1056,1057],{"class":144,"line":586},[142,1058,1059],{},"    (\"user\", \"请根据以下任务生成 Python 示例代码：{task}\")\n",[142,1061,1062],{"class":144,"line":592},[142,1063,522],{},[142,1065,1066],{"class":144,"line":598},[142,1067,180],{"emptyLinePlaceholder":179},[142,1069,1070],{"class":144,"line":604},[142,1071,1072],{},"math_agent = ChatPromptTemplate.from_messages([\n",[142,1074,1075],{"class":144,"line":610},[142,1076,1077],{},"    (\"user\", \"请解决以下数学/逻辑问题，并详细说明过程：{task}\")\n",[142,1079,1080],{"class":144,"line":616},[142,1081,522],{},[142,1083,1084],{"class":144,"line":621},[142,1085,180],{"emptyLinePlaceholder":179},[142,1087,1088],{"class":144,"line":627},[142,1089,1090],{},"# ================== 动态 Supervisor 节点 ==================\n",[142,1092,1093],{"class":144,"line":633},[142,1094,1095],{},"def supervisor_node(state: TaskState):\n",[142,1097,1098],{"class":144,"line":639},[142,1099,1100],{},"    new_round = state[\"round_count\"] + 1\n",[142,1102,1103],{"class":144,"line":645},[142,1104,180],{"emptyLinePlaceholder":179},[142,1106,1107],{"class":144,"line":650},[142,1108,1109],{},"    # 超过最大轮次，触发兜底\n",[142,1111,1112],{"class":144,"line":656},[142,1113,1114],{},"    if new_round > MAX_ROUNDS:\n",[142,1116,1117],{"class":144,"line":662},[142,1118,1119],{},"        print(f\"⚠️ 超过最大轮次 {MAX_ROUNDS}，触发兜底 → 结束任务\")\n",[142,1121,1122],{"class":144,"line":668},[142,1123,1124],{},"        return {\n",[142,1126,1128],{"class":144,"line":1127},56,[142,1129,1130],{},"            \"round_count\": new_round,\n",[142,1132,1134],{"class":144,"line":1133},57,[142,1135,1136],{},"            \"next_agent\": \"end\",\n",[142,1138,1140],{"class":144,"line":1139},58,[142,1141,1142],{},"            \"supervisor_thoughts\": \"轮次数超过上限，直接结束任务\"\n",[142,1144,1146],{"class":144,"line":1145},59,[142,1147,1148],{},"        }\n",[142,1150,1152],{"class":144,"line":1151},60,[142,1153,180],{"emptyLinePlaceholder":179},[142,1155,1157],{"class":144,"line":1156},61,[142,1158,1159],{},"    # 中文提示词，严格约束 LLM\n",[142,1161,1163],{"class":144,"line":1162},62,[142,1164,1165],{},"    prompt = f\"\"\"\n",[142,1167,1169],{"class":144,"line":1168},63,[142,1170,1171],{},"你是多智能体系统的主管智能体（Supervisor），负责调度专家智能体，但你不执行任务。请阅读当前任务和已完成状态，并选择下一步最合适的智能体执行。\n",[142,1173,1175],{"class":144,"line":1174},64,[142,1176,180],{"emptyLinePlaceholder":179},[142,1178,1180],{"class":144,"line":1179},65,[142,1181,1182],{},"任务：\n",[142,1184,1186],{"class":144,"line":1185},66,[142,1187,1188],{},"{state['task']}\n",[142,1190,1192],{"class":144,"line":1191},67,[142,1193,180],{"emptyLinePlaceholder":179},[142,1195,1197],{"class":144,"line":1196},68,[142,1198,1199],{},"已完成状态：\n",[142,1201,1203],{"class":144,"line":1202},69,[142,1204,1205],{},"- 调研: {\"已完成\" if state.get(\"research\") else \"未完成\"}\n",[142,1207,1209],{"class":144,"line":1208},70,[142,1210,1211],{},"- 写作: {\"已完成\" if state.get(\"draft\") else \"未完成\"}\n",[142,1213,1215],{"class":144,"line":1214},71,[142,1216,1217],{},"- 编程: {\"已完成\" if state.get(\"code\") else \"未完成\"}\n",[142,1219,1221],{"class":144,"line":1220},72,[142,1222,1223],{},"- 数学: {\"已完成\" if state.get(\"math\") else \"未完成\"}\n",[142,1225,1227],{"class":144,"line":1226},73,[142,1228,180],{"emptyLinePlaceholder":179},[142,1230,1232],{"class":144,"line":1231},74,[142,1233,1234],{},"可调度智能体：\n",[142,1236,1238],{"class":144,"line":1237},75,[142,1239,1240],{},"- research_agent：负责调研和整理资料\n",[142,1242,1244],{"class":144,"line":1243},76,[142,1245,1246],{},"- writer_agent：负责撰写中文文章或说明文\n",[142,1248,1250],{"class":144,"line":1249},77,[142,1251,1252],{},"- code_agent：负责编写 Python 代码\n",[142,1254,1256],{"class":144,"line":1255},78,[142,1257,1258],{},"- math_agent：负责数学/逻辑计算与推理\n",[142,1260,1262],{"class":144,"line":1261},79,[142,1263,180],{"emptyLinePlaceholder":179},[142,1265,1267],{"class":144,"line":1266},80,[142,1268,1269],{},"约束：\n",[142,1271,1273],{"class":144,"line":1272},81,[142,1274,1275],{},"1. 不能选择已完成的智能体。\n",[142,1277,1279],{"class":144,"line":1278},82,[142,1280,1281],{},"2. 必须选择与任务相关的智能体。\n",[142,1283,1285],{"class":144,"line":1284},83,[142,1286,1287],{},"3. 如果所有任务完成，返回 \"end\"。\n",[142,1289,1291],{"class":144,"line":1290},84,[142,1292,1293],{},"4. 请在回答中先写出你的“思考过程”，然后在最后一行返回下一步智能体名称（research_agent / writer_agent / code_agent / math_agent / end）。\n",[142,1295,1297],{"class":144,"line":1296},85,[142,1298,180],{"emptyLinePlaceholder":179},[142,1300,1302],{"class":144,"line":1301},86,[142,1303,1304],{},"请用中文完整回答：\n",[142,1306,1308],{"class":144,"line":1307},87,[142,1309,1310],{},"\"\"\"\n",[142,1312,1314],{"class":144,"line":1313},88,[142,1315,180],{"emptyLinePlaceholder":179},[142,1317,1319],{"class":144,"line":1318},89,[142,1320,1321],{},"    res = llm.invoke(prompt)\n",[142,1323,1325],{"class":144,"line":1324},90,[142,1326,1327],{},"    thoughts = res.content.strip()\n",[142,1329,1331],{"class":144,"line":1330},91,[142,1332,1333],{},"    last_line = thoughts.splitlines()[-1]\n",[142,1335,1337],{"class":144,"line":1336},92,[142,1338,1339],{},"    valid_agents = (\"research_agent\", \"writer_agent\", \"code_agent\", \"math_agent\", \"end\")\n",[142,1341,1343],{"class":144,"line":1342},93,[142,1344,1345],{},"    next_agent = next((a for a in valid_agents if a in last_line), \"end\")\n",[142,1347,1349],{"class":144,"line":1348},94,[142,1350,1351],{},"    print(f\"🧠 主管思考过程：\\n{thoughts}\\n\")\n",[142,1353,1355],{"class":144,"line":1354},95,[142,1356,1357],{},"    print(f\"🧠 主管调度 → {next_agent} (轮次 {new_round})\")\n",[142,1359,1361],{"class":144,"line":1360},96,[142,1362,1363],{},"    \n",[142,1365,1367],{"class":144,"line":1366},97,[142,1368,1369],{},"    return {\n",[142,1371,1373],{"class":144,"line":1372},98,[142,1374,1375],{},"        \"round_count\": new_round,\n",[142,1377,1379],{"class":144,"line":1378},99,[142,1380,1381],{},"        \"next_agent\": next_agent,\n",[142,1383,1385],{"class":144,"line":1384},100,[142,1386,1387],{},"        \"supervisor_thoughts\": thoughts\n",[142,1389,1391],{"class":144,"line":1390},101,[142,1392,805],{},[142,1394,1396],{"class":144,"line":1395},102,[142,1397,180],{"emptyLinePlaceholder":179},[142,1399,1401],{"class":144,"line":1400},103,[142,1402,1403],{},"# ================== 员工节点 ==================\n",[142,1405,1407],{"class":144,"line":1406},104,[142,1408,1409],{},"def research_node(state: TaskState):\n",[142,1411,1413],{"class":144,"line":1412},105,[142,1414,1415],{},"    print(\">>> Research Agent 执行中...\")\n",[142,1417,1419],{"class":144,"line":1418},106,[142,1420,1421],{},"    try:\n",[142,1423,1425],{"class":144,"line":1424},107,[142,1426,1427],{},"        res = research_agent.invoke({\"task\": state[\"task\"]})\n",[142,1429,1431],{"class":144,"line":1430},108,[142,1432,1433],{},"        result = res.content.strip()\n",[142,1435,1437],{"class":144,"line":1436},109,[142,1438,1439],{},"    except Exception as e:\n",[142,1441,1443],{"class":144,"line":1442},110,[142,1444,1445],{},"        result = f\"调研失败：{str(e)[:50]}\"\n",[142,1447,1449],{"class":144,"line":1448},111,[142,1450,1363],{},[142,1452,1454],{"class":144,"line":1453},112,[142,1455,1456],{},"    # ✅ 正确写法：只返回更新字段\n",[142,1458,1460],{"class":144,"line":1459},113,[142,1461,1369],{},[142,1463,1465],{"class":144,"line":1464},114,[142,1466,1467],{},"        \"research\": result,\n",[142,1469,1471],{"class":144,"line":1470},115,[142,1472,1473],{},"        \"result\": result\n",[142,1475,1477],{"class":144,"line":1476},116,[142,1478,805],{},[142,1480,1482],{"class":144,"line":1481},117,[142,1483,180],{"emptyLinePlaceholder":179},[142,1485,1487],{"class":144,"line":1486},118,[142,1488,1489],{},"def writer_node(state: TaskState):\n",[142,1491,1493],{"class":144,"line":1492},119,[142,1494,1495],{},"    print(\">>> Writer Agent 执行中...\")\n",[142,1497,1499],{"class":144,"line":1498},120,[142,1500,1421],{},[142,1502,1504],{"class":144,"line":1503},121,[142,1505,1506],{},"        res = writer_agent.invoke({\"research\": state.get(\"research\",\"\")})\n",[142,1508,1510],{"class":144,"line":1509},122,[142,1511,1433],{},[142,1513,1515],{"class":144,"line":1514},123,[142,1516,1439],{},[142,1518,1520],{"class":144,"line":1519},124,[142,1521,1522],{},"        result = f\"写作失败：{str(e)[:50]}\"\n",[142,1524,1526],{"class":144,"line":1525},125,[142,1527,1363],{},[142,1529,1531],{"class":144,"line":1530},126,[142,1532,1533],{},"    # ✅ 正确写法\n",[142,1535,1537],{"class":144,"line":1536},127,[142,1538,1369],{},[142,1540,1542],{"class":144,"line":1541},128,[142,1543,1544],{},"        \"draft\": result,\n",[142,1546,1548],{"class":144,"line":1547},129,[142,1549,1473],{},[142,1551,1553],{"class":144,"line":1552},130,[142,1554,805],{},[142,1556,1558],{"class":144,"line":1557},131,[142,1559,180],{"emptyLinePlaceholder":179},[142,1561,1563],{"class":144,"line":1562},132,[142,1564,1565],{},"def code_node(state: TaskState):\n",[142,1567,1569],{"class":144,"line":1568},133,[142,1570,1571],{},"    print(\">>> Code Agent 执行中...\")\n",[142,1573,1575],{"class":144,"line":1574},134,[142,1576,1421],{},[142,1578,1580],{"class":144,"line":1579},135,[142,1581,1582],{},"        res = code_agent.invoke({\"task\": state[\"task\"]})\n",[142,1584,1586],{"class":144,"line":1585},136,[142,1587,1433],{},[142,1589,1591],{"class":144,"line":1590},137,[142,1592,1439],{},[142,1594,1596],{"class":144,"line":1595},138,[142,1597,1598],{},"        result = f\"代码生成失败：{str(e)[:50]}\"\n",[142,1600,1602],{"class":144,"line":1601},139,[142,1603,1363],{},[142,1605,1607],{"class":144,"line":1606},140,[142,1608,1533],{},[142,1610,1612],{"class":144,"line":1611},141,[142,1613,1369],{},[142,1615,1617],{"class":144,"line":1616},142,[142,1618,1619],{},"        \"code\": result,\n",[142,1621,1623],{"class":144,"line":1622},143,[142,1624,1473],{},[142,1626,1628],{"class":144,"line":1627},144,[142,1629,805],{},[142,1631,1633],{"class":144,"line":1632},145,[142,1634,180],{"emptyLinePlaceholder":179},[142,1636,1638],{"class":144,"line":1637},146,[142,1639,1640],{},"def math_node(state: TaskState):\n",[142,1642,1644],{"class":144,"line":1643},147,[142,1645,1646],{},"    print(\">>> Math Agent 执行中...\")\n",[142,1648,1650],{"class":144,"line":1649},148,[142,1651,1421],{},[142,1653,1655],{"class":144,"line":1654},149,[142,1656,1657],{},"        res = math_agent.invoke({\"task\": state[\"task\"]})\n",[142,1659,1661],{"class":144,"line":1660},150,[142,1662,1433],{},[142,1664,1666],{"class":144,"line":1665},151,[142,1667,1439],{},[142,1669,1671],{"class":144,"line":1670},152,[142,1672,1673],{},"        result = f\"数学求解失败：{str(e)[:50]}\"\n",[142,1675,1677],{"class":144,"line":1676},153,[142,1678,1363],{},[142,1680,1682],{"class":144,"line":1681},154,[142,1683,1533],{},[142,1685,1687],{"class":144,"line":1686},155,[142,1688,1369],{},[142,1690,1692],{"class":144,"line":1691},156,[142,1693,1694],{},"        \"math\": result,\n",[142,1696,1698],{"class":144,"line":1697},157,[142,1699,1473],{},[142,1701,1703],{"class":144,"line":1702},158,[142,1704,805],{},[142,1706,1708],{"class":144,"line":1707},159,[142,1709,180],{"emptyLinePlaceholder":179},[142,1711,1713],{"class":144,"line":1712},160,[142,1714,1715],{},"# ================== 构建 LangGraph ==================\n",[142,1717,1719],{"class":144,"line":1718},161,[142,1720,1721],{},"workflow = StateGraph(TaskState)\n",[142,1723,1725],{"class":144,"line":1724},162,[142,1726,180],{"emptyLinePlaceholder":179},[142,1728,1730],{"class":144,"line":1729},163,[142,1731,1732],{},"workflow.add_node(\"supervisor\", supervisor_node)\n",[142,1734,1736],{"class":144,"line":1735},164,[142,1737,1738],{},"workflow.add_node(\"research_agent\", research_node)\n",[142,1740,1742],{"class":144,"line":1741},165,[142,1743,1744],{},"workflow.add_node(\"writer_agent\", writer_node)\n",[142,1746,1748],{"class":144,"line":1747},166,[142,1749,1750],{},"workflow.add_node(\"code_agent\", code_node)\n",[142,1752,1754],{"class":144,"line":1753},167,[142,1755,1756],{},"workflow.add_node(\"math_agent\", math_node)\n",[142,1758,1760],{"class":144,"line":1759},168,[142,1761,180],{"emptyLinePlaceholder":179},[142,1763,1765],{"class":144,"line":1764},169,[142,1766,1767],{},"workflow.add_edge(START, \"supervisor\")\n",[142,1769,1771],{"class":144,"line":1770},170,[142,1772,180],{"emptyLinePlaceholder":179},[142,1774,1776],{"class":144,"line":1775},171,[142,1777,1778],{},"workflow.add_conditional_edges(\n",[142,1780,1782],{"class":144,"line":1781},172,[142,1783,1784],{},"    \"supervisor\",\n",[142,1786,1788],{"class":144,"line":1787},173,[142,1789,1790],{},"    lambda s: s[\"next_agent\"],\n",[142,1792,1794],{"class":144,"line":1793},174,[142,1795,1796],{},"    {\n",[142,1798,1800],{"class":144,"line":1799},175,[142,1801,1802],{},"        \"research_agent\": \"research_agent\",\n",[142,1804,1806],{"class":144,"line":1805},176,[142,1807,1808],{},"        \"writer_agent\": \"writer_agent\",\n",[142,1810,1812],{"class":144,"line":1811},177,[142,1813,1814],{},"        \"code_agent\": \"code_agent\",\n",[142,1816,1818],{"class":144,"line":1817},178,[142,1819,1820],{},"        \"math_agent\": \"math_agent\",\n",[142,1822,1824],{"class":144,"line":1823},179,[142,1825,1826],{},"        \"end\": END\n",[142,1828,1830],{"class":144,"line":1829},180,[142,1831,805],{},[142,1833,1835],{"class":144,"line":1834},181,[142,1836,226],{},[142,1838,1840],{"class":144,"line":1839},182,[142,1841,180],{"emptyLinePlaceholder":179},[142,1843,1845],{"class":144,"line":1844},183,[142,1846,1847],{},"workflow.add_edge(\"research_agent\", \"supervisor\")\n",[142,1849,1851],{"class":144,"line":1850},184,[142,1852,1853],{},"workflow.add_edge(\"writer_agent\", \"supervisor\")\n",[142,1855,1857],{"class":144,"line":1856},185,[142,1858,1859],{},"workflow.add_edge(\"code_agent\", \"supervisor\")\n",[142,1861,1863],{"class":144,"line":1862},186,[142,1864,1865],{},"workflow.add_edge(\"math_agent\", \"supervisor\")\n",[142,1867,1869],{"class":144,"line":1868},187,[142,1870,180],{"emptyLinePlaceholder":179},[142,1872,1874],{"class":144,"line":1873},188,[142,1875,748],{},[11,1877,751],{},[11,1879,1880],{},[28,1881],{"alt":24,"src":1882},"/assets/agent-intro/agent.png",[96,1884,1885],{"start":183},[99,1886,231],{},[15,1888,1890],{"className":165,"code":1889,"language":167,"meta":24,"style":24},"# ================== 运行示例 ==================\nif __name__ == \"__main__\":\n    tasks = [\n        \"撰写一篇介绍 LangGraph 多智能体协作的中文文章，面向初学者\",\n    ]\n\n    for t in tasks:\n        print(\"\\n\" + \"=\"*50)\n        print(f\"任务：{t}\")\n        init_state = {\n            \"task\": t,\n            \"research\": None,\n            \"draft\": None,\n            \"code\": None,\n            \"math\": None,\n            \"next_agent\": None,\n            \"result\": None,\n            \"round_count\": 0,\n            \"supervisor_thoughts\": None\n        }\n        result = app.invoke(init_state)\n        print(\"\\n✅ 最终结果：\\n\", result[\"result\"])\n",[22,1891,1892,1897,1901,1906,1911,1916,1920,1925,1930,1935,1940,1945,1950,1955,1960,1965,1970,1975,1980,1985,1989,1994],{"__ignoreMap":24},[142,1893,1894],{"class":144,"line":145},[142,1895,1896],{},"# ================== 运行示例 ==================\n",[142,1898,1899],{"class":144,"line":130},[142,1900,775],{},[142,1902,1903],{"class":144,"line":183},[142,1904,1905],{},"    tasks = [\n",[142,1907,1908],{"class":144,"line":189},[142,1909,1910],{},"        \"撰写一篇介绍 LangGraph 多智能体协作的中文文章，面向初学者\",\n",[142,1912,1913],{"class":144,"line":194},[142,1914,1915],{},"    ]\n",[142,1917,1918],{"class":144,"line":200},[142,1919,180],{"emptyLinePlaceholder":179},[142,1921,1922],{"class":144,"line":205},[142,1923,1924],{},"    for t in tasks:\n",[142,1926,1927],{"class":144,"line":211},[142,1928,1929],{},"        print(\"\\n\" + \"=\"*50)\n",[142,1931,1932],{"class":144,"line":217},[142,1933,1934],{},"        print(f\"任务：{t}\")\n",[142,1936,1937],{"class":144,"line":223},[142,1938,1939],{},"        init_state = {\n",[142,1941,1942],{"class":144,"line":287},[142,1943,1944],{},"            \"task\": t,\n",[142,1946,1947],{"class":144,"line":292},[142,1948,1949],{},"            \"research\": None,\n",[142,1951,1952],{"class":144,"line":297},[142,1953,1954],{},"            \"draft\": None,\n",[142,1956,1957],{"class":144,"line":303},[142,1958,1959],{},"            \"code\": None,\n",[142,1961,1962],{"class":144,"line":309},[142,1963,1964],{},"            \"math\": None,\n",[142,1966,1967],{"class":144,"line":315},[142,1968,1969],{},"            \"next_agent\": None,\n",[142,1971,1972],{"class":144,"line":321},[142,1973,1974],{},"            \"result\": None,\n",[142,1976,1977],{"class":144,"line":327},[142,1978,1979],{},"            \"round_count\": 0,\n",[142,1981,1982],{"class":144,"line":460},[142,1983,1984],{},"            \"supervisor_thoughts\": None\n",[142,1986,1987],{"class":144,"line":466},[142,1988,1148],{},[142,1990,1991],{"class":144,"line":472},[142,1992,1993],{},"        result = app.invoke(init_state)\n",[142,1995,1996],{"class":144,"line":478},[142,1997,1998],{},"        print(\"\\n✅ 最终结果：\\n\", result[\"result\"])\n",[32,2000,2002],{"id":2001},"_2-现代-agent-的发展","2. 现代 agent 的发展",[15,2004,2007],{"className":2005,"code":2006,"language":20},[18],"┌──────────────────────────────────────────────┐\n│ 第一部分：chatbot                             │\n│ Token(Memory) → Prompt Engineering           │\n└──────────────────────────────────────────────┘\n               ↓\n┌──────────────────────────────────────────────────────────────────────────────┐\n│ 第二部分：机器 辅助 人                                                         │\n│ RAG → Tool Calling → MCP → Context Engineering → Skills → Computer Use(CLI)  │\n└──────────────────────────────────────────────────────────────────────────────┘\n               ↓\n┌────────────────────────────────────────────────────┐\n│ 第三部分：人 辅助 机器                               │\n│ Agent(范式、AICodingAgent) → Harness Engineering    │\n└────────────────────────────────────────────────────┘\n               ↓\n┌──────────────────────────────────┐\n│ 第四部分：机器独立                 │\n│ Workflow → Workspace Agent(IM)   │\n└──────────────────────────────────┘\n",[22,2008,2006],{"__ignoreMap":24},[32,2010,2012],{"id":2011},"_3-技术路线选讲","3. 技术路线选讲",[103,2014,2015],{},[11,2016,2017],{},"Tool Calling 线",[15,2019,2022],{"className":2020,"code":2021,"language":20},[18],"┌──────────────────────────────────────────────────┐\n│ Tool Calling 线                                  │\n│ function calling + API -> MCPs -> CLI + skills   │\n└──────────────────────────────────────────────────┘\n",[22,2023,2021],{"__ignoreMap":24},[32,2025,2027],{"id":2026},"_31-function-calling-api","3.1 function calling + API",[91,2029,2031],{"id":2030},"_311-api示例","3.1.1. API示例：",[15,2033,2035],{"className":165,"code":2034,"language":167,"meta":24,"style":24},"import requests\n\ndef search_poi(keywords: str,city: str,api_key: str):\n    \"\"\"直接调用高德地图POI搜索API\"\"\"\n    url = \"https://restapi.amap.com/v3/place/text\"\n    params = {\n        \"keywords\": keywords,\n        \"city\": city,\n        \"key\": api_key,\n        \"output\": \"json\"\n    }\n    response = requests.get(url,params=params)\n    data = response.json()\n    return data\n\n",[22,2036,2037,2042,2046,2051,2056,2061,2066,2071,2076,2081,2086,2090,2095,2100],{"__ignoreMap":24},[142,2038,2039],{"class":144,"line":145},[142,2040,2041],{},"import requests\n",[142,2043,2044],{"class":144,"line":130},[142,2045,180],{"emptyLinePlaceholder":179},[142,2047,2048],{"class":144,"line":183},[142,2049,2050],{},"def search_poi(keywords: str,city: str,api_key: str):\n",[142,2052,2053],{"class":144,"line":189},[142,2054,2055],{},"    \"\"\"直接调用高德地图POI搜索API\"\"\"\n",[142,2057,2058],{"class":144,"line":194},[142,2059,2060],{},"    url = \"https://restapi.amap.com/v3/place/text\"\n",[142,2062,2063],{"class":144,"line":200},[142,2064,2065],{},"    params = {\n",[142,2067,2068],{"class":144,"line":205},[142,2069,2070],{},"        \"keywords\": keywords,\n",[142,2072,2073],{"class":144,"line":211},[142,2074,2075],{},"        \"city\": city,\n",[142,2077,2078],{"class":144,"line":217},[142,2079,2080],{},"        \"key\": api_key,\n",[142,2082,2083],{"class":144,"line":223},[142,2084,2085],{},"        \"output\": \"json\"\n",[142,2087,2088],{"class":144,"line":287},[142,2089,805],{},[142,2091,2092],{"class":144,"line":292},[142,2093,2094],{},"    response = requests.get(url,params=params)\n",[142,2096,2097],{"class":144,"line":297},[142,2098,2099],{},"    data = response.json()\n",[142,2101,2102],{"class":144,"line":303},[142,2103,2104],{},"    return data\n",[91,2106,2108],{"id":2107},"_312-api流程总结","3.1.2. API流程总结：",[15,2110,2113],{"className":2111,"code":2112,"language":20},[18],"1. 知道服务器位置（本地/URL）\n2. 知道 本系统的输出参数格式 + 服务器需要的输入参数格式 -- 打包\n3. 知道 服务器的输出参数格式 + 本系统需要的输入参数格式 -- 解包\n",[22,2114,2112],{"__ignoreMap":24},[91,2116,2118],{"id":2117},"_313-api问题总结用mcps","3.1.3. API问题总结（用MCPs）:",[15,2120,2123],{"className":2121,"code":2122,"language":20},[18],"# 一切源于 打包+解包 的苛刻要求\n\n1. 服务器更新(响应格式) -- 你的 API处理代码 也需要变\n2. 如果要增加 服务器支持(系统功能扩展) -- 你需要 重新写 新功能的API处理代码\n3. 你的代码 不适配类似的系统\n",[22,2124,2122],{"__ignoreMap":24},[91,2126,2128],{"id":2127},"_314-api困难分析用mcps","3.1.4. API困难分析（用MCPs）：",[15,2130,2133],{"className":2131,"code":2132,"language":20},[18],"直接使用API的代码看起来很简单，但在实际使用中会遇到几个问题：\n1. 首先是Agent 无法自主调用。在我们的 sibuchen-agents 框架中，Agent 通过识别提示词中的工具调用标记(比如[TOOL_CALL:tool_name:arg1=value1])来调用工具。如果我们直接在代码中调用 API，Agent 就失去了自主决策的能力，变成了一个简单的函数调用。 -- 解决方法：封装成工具 -- MCPs（tools 的集合）\n\n2. 参数传递复杂。高德地图的 API 有很多参数，比如 POI 搜索有keywords、city、types、offset、page等十几个参数。如果我们要让 Agent 能够灵活使用这些参数，就需要在提示词中详细说明每个参数的含义和格式，这会让提示词变得非常复杂。 -- 解决方法：构建skills -- 模型上下文协议（MCP，提供tool的上下文信息）\n\n3. 响应解析困难。高德地图 API 返回的是 JSON 格式的数据，结构比较复杂。我们需要编写代码来解析这些数据，提取我们需要的字段。如果 API 的响应格式发生变化，我们就需要修改解析代码。 -- 重点：程序员的开发困难 -- 经典的3个问题 -- 抽象类（MCP）\n\n4. 工具管理混乱。高德地图提供了十几个不同的 API(POI 搜索、天气查询、路线规划等)，如果我们为每个 API 都编写一个函数，然后手动注册到 Agent 的工具列表中，代码会变得很冗长。而且当我们想添加新的 API 时，需要修改多个地方。 -- 重点：程序员的开发困难 -- MCPs 对 同系列tools 的封装 -- 类（MCPs）\n",[22,2134,2132],{"__ignoreMap":24},[32,2136,2138],{"id":2137},"_32-mcps","3.2 MCPs",[91,2140,2142],{"id":2141},"_321-mcps代码示例","3.2.1. MCPs代码示例：",[15,2144,2146],{"className":165,"code":2145,"language":167,"meta":24,"style":24},"from sibuchen_agents.tools import MCPTool\nfrom app.config import get_settings\n\nsettings = get_settings()\n\n# 创建MCP工具\nmcp_tool = MCPTool(\n    name=\"amap_mcp\",\n    command=\"npx\",\n    args=[\"-y\", \"@sugarforever/amap-mcp-server\"],\n    env={\"AMAP_API_KEY\": settings.amap_api_key},\n    auto_expand=True\n)\n",[22,2147,2148,2153,2158,2162,2167,2171,2176,2181,2186,2191,2196,2201,2206],{"__ignoreMap":24},[142,2149,2150],{"class":144,"line":145},[142,2151,2152],{},"from sibuchen_agents.tools import MCPTool\n",[142,2154,2155],{"class":144,"line":130},[142,2156,2157],{},"from app.config import get_settings\n",[142,2159,2160],{"class":144,"line":183},[142,2161,180],{"emptyLinePlaceholder":179},[142,2163,2164],{"class":144,"line":189},[142,2165,2166],{},"settings = get_settings()\n",[142,2168,2169],{"class":144,"line":194},[142,2170,180],{"emptyLinePlaceholder":179},[142,2172,2173],{"class":144,"line":200},[142,2174,2175],{},"# 创建MCP工具\n",[142,2177,2178],{"class":144,"line":205},[142,2179,2180],{},"mcp_tool = MCPTool(\n",[142,2182,2183],{"class":144,"line":211},[142,2184,2185],{},"    name=\"amap_mcp\",\n",[142,2187,2188],{"class":144,"line":217},[142,2189,2190],{},"    command=\"npx\",\n",[142,2192,2193],{"class":144,"line":223},[142,2194,2195],{},"    args=[\"-y\", \"@sugarforever/amap-mcp-server\"],\n",[142,2197,2198],{"class":144,"line":287},[142,2199,2200],{},"    env={\"AMAP_API_KEY\": settings.amap_api_key},\n",[142,2202,2203],{"class":144,"line":292},[142,2204,2205],{},"    auto_expand=True\n",[142,2207,2208],{"class":144,"line":297},[142,2209,226],{},[91,2211,2213],{"id":2212},"_322-mcp-工具调用流程","3.2.2. MCP 工具调用流程：",[11,2215,751],{},[11,2217,2218],{},[28,2219],{"alt":24,"src":2220},"/assets/agent-intro/MCP%E5%B7%A5%E5%85%B7%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B.png",[103,2222,2223],{},[11,2224,2225],{},"以前：Agent -- API",[103,2227,2228],{},[11,2229,2230],{},"现在：Agent(mcp_host) -- MCPTool(mcp_client) -- MCPs(mcp_server) -- API(原API服务)",[103,2232,2233],{},[11,2234,2235],{},"现在：Agent(+ skills) -- TerminalTool -- CLI(下载npx/uvx/... + 运行环境)",[11,2237,2238],{},"具体流程解析：",[15,2240,2243],{"className":2241,"code":2242,"language":20},[18],"1. LLM 生成工具调用标记：[TOOL_CALL:amap_maps_text_search:keywords=景点，city=北京]。\n2. sibuchen-agents 框架解析这个标记，提取 工具名称 和 参数 ，然后依据 工具名称 调用对应的 Tool对象，传递 参数。\n3. Tool 对象是MCPTool自动创建的。接收到参数后，它会构造一个 JSON-RPC 格式的消息，再把调用消息发送给 MCP 服务器（例如，通过 stdin 发送给服务器进程）：\n\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"tools/call\",\n  \"params\": {\n    \"name\": \"amap_maps_text_search\",\n    \"arguments\": {\n      \"keywords\": \"景点\",\n      \"city\": \"北京\"\n    }\n  }\n}\n\n\n4. MCP 服务器接收到这个消息，解析参数，运行代码解决问题(很少有) 或者 调用高德地图的 HTTP API 解决问题（主要）。它会构造 HTTP 请求，添加 API 密钥，发送请求，接收响应。\n\n5. 高德地图 API 接收请求，运行代码，并最终返回 JSON 格式的数据。其包含景点列表 、地址、坐标等信息。\n6. MCP 服务器解析这些数据，提取关键字段，然后构造响应消息，通过 stdout 返回给MCPTool：\n\n{\n  \"jsonrpc\": \"2.0\",\n  \"result\": {\n    \"content\": [\n      {\n        \"type\": \"text\",\n        \"text\": \"找到以下景点：\\n1. 故宫博物院 - 地址：东城区景山前街4号\\n2. 天坛公园 - 地址：东城区天坛路\\n...\"\n      }\n    ]\n  }\n}\n\n7. MCPTool接收到响应，提取文本内容，通过 sibuchen-agents 架构 将结果返回给 LLM（工具调用结果回注）。\n8. LLM 把这个结果作为工具调用的输出，继续生成最终的回复。\n",[22,2244,2242],{"__ignoreMap":24},[103,2246,2247],{},[11,2248,2249],{},"这个流程看起来很复杂，但对于 Agent 来说，它只需要知道有一个叫amap_maps_text_search的工具，可以搜索景点。所有的底层细节都被 MCP 协议和MCPTool封装起来了。",[91,2251,2253],{"id":2252},"_323-mcps-补充知识","3.2.3. MCPs 补充知识",[96,2255,2256],{},[99,2257,2258],{},"三个组件",[15,2260,2263],{"className":2261,"code":2262,"language":20},[18],"Host 是 “最终应用”\nClient 是 “协议通信模块”\nServer 是 “工具提供者”\n\n---\n\nHost\n  └── Client\n         ↓\n       Server\n",[22,2264,2262],{"__ignoreMap":24},[11,2266,2267],{},"举个例子：",[15,2269,2272],{"className":2270,"code":2271,"language":20},[18],"（应用）\nCursor\n ├── UI\n ├── Agent\n ├── MCP Client\n └── LLM\n\n（外部）\nfilesystem MCP Server\n\n（组件分析）\nCursor = Host （整个 AI 应用）\n其中的 MCP 模块 = Client （Host 内部的 MCP 通信模块）\nfilesystem = Server （AI 应用 外部的服务）\n",[22,2273,2271],{"__ignoreMap":24},[11,2275,2276],{},"MCP 本质上是 Client 调用 Server, 而不是 Host 调用 Server",[2278,2279],"hr",{},[96,2281,2282],{"start":130},[99,2283,2284],{},"五种传输方式 & 两种类型",[103,2286,2287],{},[11,2288,2289],{},"MCP 协议：规定双方说话的 格式",[103,2291,2292],{},[11,2293,2294],{},"传输方式：规定双方说话的 渠道",[37,2296,2297,2318],{},[40,2298,2299],{},[43,2300,2301,2304,2306,2309,2312,2315],{},[46,2302,2303],{},"传输方式",[46,2305,66],{},[46,2307,2308],{},"适合什么",[46,2310,2311],{},"类型",[46,2313,2314],{},"部署方式",[46,2316,2317],{},"例子",[59,2319,2320,2340,2358,2378,2395],{},[43,2321,2322,2325,2328,2331,2334,2337],{},[64,2323,2324],{},"Memory",[64,2326,2327],{},"函数调用",[64,2329,2330],{},"CS同进程内部",[64,2332,2333],{},"本地 MCP Server",[64,2335,2336],{},"子进程",[64,2338,2339],{},"内置的本地 python tool",[43,2341,2342,2345,2348,2351,2353,2355],{},[64,2343,2344],{},"Stdio",[64,2346,2347],{},"进程管道",[64,2349,2350],{},"S为本地其它服务",[64,2352,2333],{},[64,2354,2336],{},[64,2356,2357],{},"filesystem、git、sqlite、terminal、独立的本地 python tool",[43,2359,2360,2363,2366,2369,2372,2375],{},[64,2361,2362],{},"HTTP",[64,2364,2365],{},"请求响应",[64,2367,2368],{},"S为远程服务",[64,2370,2371],{},"远程 MCP Server",[64,2373,2374],{},"Web服务",[64,2376,2377],{},"Notion MCP、公司内部 AI 服务、SaaS Tool",[43,2379,2380,2383,2386,2389,2391,2393],{},[64,2381,2382],{},"SSE",[64,2384,2385],{},"服务端流推送",[64,2387,2388],{},"流式输出模式",[64,2390,2371],{},[64,2392,2374],{},[64,2394],{},[43,2396,2397,2400,2403,2406,2408,2410],{},[64,2398,2399],{},"StreamableHTTP",[64,2401,2402],{},"双向流",[64,2404,2405],{},"更高级的实时通信",[64,2407,2371],{},[64,2409,2374],{},[64,2411],{},[11,2413,2414],{},"MCP:",[15,2416,2420],{"className":2417,"code":2418,"language":2419,"meta":24,"style":24},"language-JSON shiki shiki-themes github-light github-dark","{\n  \"method\": \"tools/call\",\n  \"params\": {\n    \"name\": \"weather\",\n    \"arguments\": {\n      \"city\": \"beijing\"\n    }\n  }\n}\n","JSON",[22,2421,2422,2427,2432,2437,2442,2447,2452,2456,2461],{"__ignoreMap":24},[142,2423,2424],{"class":144,"line":145},[142,2425,2426],{},"{\n",[142,2428,2429],{"class":144,"line":130},[142,2430,2431],{},"  \"method\": \"tools/call\",\n",[142,2433,2434],{"class":144,"line":183},[142,2435,2436],{},"  \"params\": {\n",[142,2438,2439],{"class":144,"line":189},[142,2440,2441],{},"    \"name\": \"weather\",\n",[142,2443,2444],{"class":144,"line":194},[142,2445,2446],{},"    \"arguments\": {\n",[142,2448,2449],{"class":144,"line":200},[142,2450,2451],{},"      \"city\": \"beijing\"\n",[142,2453,2454],{"class":144,"line":205},[142,2455,805],{},[142,2457,2458],{"class":144,"line":211},[142,2459,2460],{},"  }\n",[142,2462,2463],{"class":144,"line":217},[142,2464,2465],{},"}\n",[11,2467,2468],{},"Memory:",[103,2470,2471],{},[11,2472,2473],{},"client -> function() -> server",[15,2475,2478],{"className":2476,"code":2477,"language":20},[18],"同一进程内\n\n---\n\n┌─────────────────┐\n│ Host            │\n│  ├── Client     │\n│  └── Server     │\n└─────────────────┘\n",[22,2479,2477],{"__ignoreMap":24},[11,2481,2482],{},"Stdio:",[103,2484,2485],{},[11,2486,2487],{},"client -> stdin/stdout -> server",[103,2489,2490],{},[11,2491,2492],{},"Host 启动 Server, 传 JSON",[15,2494,2497],{"className":2495,"code":2496,"language":20},[18],"Host进程\n  └── Client\n\nServer子进程\n\n---\n\n┌────────────────────┐\n│ Claude Desktop     │\n│   └── MCP Client   │\n└─────────┬──────────┘\n          │ stdin/stdout\n┌─────────▼──────────┐\n│ MCP Server         │\n│ filesystem.py      │\n└────────────────────┘\n",[22,2498,2496],{"__ignoreMap":24},[11,2500,2501],{},"HTTP:",[103,2503,2504],{},[11,2505,2506],{},"client -> HTTP POST -> server",[103,2508,2509],{},[11,2510,2511],{},"Host 不负责启动 Server, Server 已经运行着",[15,2513,2516],{"className":2514,"code":2515,"language":20},[18],"Client 和 Server 机器分离\n---\n┌─────────────────┐        HTTP       ┌─────────────────┐\n│ Host            │ ───────────────▶ │ MCP Server      │\n│  └── Client     │                  │ FastAPI         │\n└─────────────────┘                  └─────────────────┘\n",[22,2517,2515],{"__ignoreMap":24},[11,2519,2520],{},"SSE（Server-Sent Events）:",[103,2522,2523],{},[11,2524,2525],{},"client -> HTTP -> server -> stream -> client (流式的 HTTP)",[15,2527,2530],{"className":2528,"code":2529,"language":20},[18],"结构类似 HTTP, server 持续推送\n---\n┌─────────────────┐\n│ Host            │\n│  └── Client     │\n└────────┬────────┘\n         │ HTTP\n         ▼\n┌─────────────────┐\n│ MCP Server      │\n│  持续stream输出  │\n└─────────────────┘\n",[22,2531,2529],{"__ignoreMap":24},[11,2533,2534],{},"StreamableHTTP:",[103,2536,2537],{},[11,2538,2539],{},"client -> HTTP + 双向流 -> server (比 SSE 更高级)",[15,2541,2544],{"className":2542,"code":2543,"language":20},[18],"长连接 + 双向流\n---\n┌─────────────────┐  bidirectional stream ┌─────────────────┐\n│ Host            │ ◀──────────────────▶ │ MCP Server      │\n│  └── Client     │                       │                 │\n└─────────────────┘                       └─────────────────┘\n",[22,2545,2543],{"__ignoreMap":24},[11,2547,2548],{},"代码示例：",[15,2550,2553],{"className":2551,"code":2552,"language":20},[18],"# 1. Memory Transport - 内存传输（用于测试）\n# 不指定任何参数，使用内置演示服务器\nmcp_tool = MCPTool()\n\n# 2.1.1. Stdio Transport - 标准输入输出传输（本地开发）\n# 使用命令列表启动本地服务器\nmcp_tool = MCPTool(server_command=[\"python\", \"examples/mcp_example_server.py\"])\n\n# 2.1.2. Stdio Transport with Args - 带参数的命令传输\n# 可以传递额外参数\nmcp_tool = MCPTool(server_command=[\"python\", \"examples/mcp_example_server.py\", \"--debug\"])\n\n# 2.2. Stdio Transport - 社区服务器（npx方式）\n# 使用npx启动社区MCP服务器\nmcp_tool = MCPTool(server_command=[\"npx\", \"-y\", \"@modelcontextprotocol/server-filesystem\", \".\"])\n",[22,2554,2552],{"__ignoreMap":24},[103,2556,2557],{},[11,2558,2559],{},"注意：MCPTool主要用于Stdio和Memory传输。对于HTTP/SSE等远程传输，建议直接使用MCPClient",[15,2561,2564],{"className":2562,"code":2563,"language":20},[18],"# 3. HTTP Transport - 连接到远程 HTTP MCP 服务器\nclient = MCPClient(\"http://api.example.com/mcp\")\n\n# 4. HTTP Transport - 连接到远程 SSE MCP 服务器\nclient = MCPClient(\n    \"http://localhost:8080/sse\",\n    transport_type=\"sse\"\n)\n\n# 5. HTTP Transport - 连接到远程 StreamableHTTP MCP 服务器\nclient = MCPClient(\n    \"http://localhost:8080/mcp\",\n    transport_type=\"streamable_http\"\n)\n",[22,2565,2563],{"__ignoreMap":24},[91,2567,2569],{"id":2568},"_324-mcps使用总结","3.2.4. MCPs使用总结：",[15,2571,2574],{"className":2572,"code":2573,"language":20},[18],"mcp_host = agent = 与你交互 的地方\nmcp_client = mcp_tool = 系统中获取参数 调用MCPs 返回结果 的地方\nmcp_server = mcp_server（本地 - npx/uvx/... - stdio，云端 - url - http） = 外部提供服务(函数) 的地方\n额外服务 = mcp_server 利用 http 自行解决 （可能需要 .env 的 API_key）\n",[22,2575,2573],{"__ignoreMap":24},[91,2577,2579],{"id":2578},"_325-mcps的缺点-用mcpscliskills","3.2.5. MCPs的缺点 （用MCPs,CLI+skills）",[103,2581,2582],{},[11,2583,2584],{},"MCPs -- 重 慢 但是 安全 安全",[103,2586,2587],{},[11,2588,2589],{},"更多请看 Agent通信协议.md",[15,2591,2594],{"className":2592,"code":2593,"language":20},[18],"# 一切源于 模型上下文协议 的 工具上下文\n\n1. MCPs = n个tool，tool 含 工具上下文，工具上下文 = 使用权限 + 输入格式 + 输出格式 + 相关依赖 + ...\n2. 工具上下文 = 使用权限 + 输入格式 + 输出格式 + 相关依赖 + ...\n\n3. 以处理照片为例：LLM 要不断选择 MCPs 中的 tools (多轮交互); LLM 只用输出一个 CLI 命令 (一轮交互)\n4. LLM只能使用MCPs中的定义：固定输出 固定输入\n",[22,2595,2593],{"__ignoreMap":24},[91,2597,2599],{"id":2598},"_326-mcps-个人看法与思考","3.2.6. MCPs 个人看法与思考",[96,2601,2602,2605,2608],{},[99,2603,2604],{},"MCPs 很重（一个 MCPs , 加载所有Tools, 一个Tool的内容全部注入上下文） 但是很安全（格式/权限确定）",[99,2606,2607],{},"MCPs ≈ （skills）插件， tool（全部注入） ≈ skill（渐进式披露）",[99,2609,2610],{},"\" CLI + skill \" 的方案 只替代了 \" 本地MCPs（传统/新的CLI工具） + 部分远程MCPs \" (因为安全性)",[37,2612,2613,2632],{},[40,2614,2615],{},[43,2616,2617,2620,2623,2626,2629],{},[46,2618,2619],{},"集合",[46,2621,2622],{},"元素",[46,2624,2625],{},"格式",[46,2627,2628],{},"技术",[46,2630,2631],{},"安全（源于技术）",[59,2633,2634,2651,2668,2685],{},[43,2635,2636,2639,2642,2645,2648],{},[64,2637,2638],{},"API",[64,2640,2641],{},"endpoint",[64,2643,2644],{},"HTTP/JSON",[64,2646,2647],{},"RPC 调用",[64,2649,2650],{},"Token/鉴权",[43,2652,2653,2656,2659,2662,2665],{},[64,2654,2655],{},"MCPs",[64,2657,2658],{},"tool",[64,2660,2661],{},"MCP",[64,2663,2664],{},"上下文注入 + Tool Calling + 全注入",[64,2666,2667],{},"细粒度权限",[43,2669,2670,2673,2676,2679,2682],{},[64,2671,2672],{},"Plugin",[64,2674,2675],{},"skill",[64,2677,2678],{},"Markdown + Assets",[64,2680,2681],{},"Prompt 组织 + 渐进式披露",[64,2683,2684],{},"弱权限模型",[43,2686,2687,2690,2693,2696,2699],{},[64,2688,2689],{},"CLI",[64,2691,2692],{},"command",[64,2694,2695],{},"Shell Command",[64,2697,2698],{},"Process 调用",[64,2700,2701],{},"系统权限边界",[32,2703,2705],{"id":2704},"_33-cli-skills","3.3. CLI + skills",[91,2707,2709],{"id":2708},"_331-安装cli","3.3.1. 安装CLI",[15,2711,2713],{"className":136,"code":2712,"language":138,"meta":24,"style":24},"npm install -g @playwright/cli@latest\n",[22,2714,2715],{"__ignoreMap":24},[142,2716,2717,2720,2722,2726],{"class":144,"line":145},[142,2718,2719],{"class":148},"npm",[142,2721,153],{"class":152},[142,2723,2725],{"class":2724},"sj4cs"," -g",[142,2727,2728],{"class":152}," @playwright/cli@latest\n",[91,2730,2732],{"id":2731},"_332-安装对应的-skill","3.3.2. 安装对应的 skill",[15,2734,2736],{"className":136,"code":2735,"language":138,"meta":24,"style":24},"playwright-cli install --skills\n",[22,2737,2738],{"__ignoreMap":24},[142,2739,2740,2743,2745],{"class":144,"line":145},[142,2741,2742],{"class":148},"playwright-cli",[142,2744,153],{"class":152},[142,2746,2747],{"class":2724}," --skills\n",[91,2749,2751],{"id":2750},"_333-启动-claudecode","3.3.3. 启动 ClaudeCode",[15,2753,2755],{"className":136,"code":2754,"language":138,"meta":24,"style":24},"claude\n",[22,2756,2757],{"__ignoreMap":24},[142,2758,2759],{"class":144,"line":145},[142,2760,2754],{"class":148},[91,2762,2764],{"id":2763},"_334-have-a-try","3.3.4. have a try",[15,2766,2769],{"className":2767,"code":2768,"language":20},[18],"/playwright-cli 使用参数--headed --persistent 打开广东财经大学的大数据与人工智能学院的官网,爬取网页的前端设计\n",[22,2770,2768],{"__ignoreMap":24},[2772,2773,2774],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":24,"searchDepth":130,"depth":130,"links":2776},[2777,2782,2783,2784,2790,2798],{"id":34,"depth":130,"text":35,"children":2778},[2779,2780,2781],{"id":93,"depth":183,"text":94},{"id":332,"depth":183,"text":333},{"id":855,"depth":183,"text":856},{"id":2001,"depth":130,"text":2002},{"id":2011,"depth":130,"text":2012},{"id":2026,"depth":130,"text":2027,"children":2785},[2786,2787,2788,2789],{"id":2030,"depth":183,"text":2031},{"id":2107,"depth":183,"text":2108},{"id":2117,"depth":183,"text":2118},{"id":2127,"depth":183,"text":2128},{"id":2137,"depth":130,"text":2138,"children":2791},[2792,2793,2794,2795,2796,2797],{"id":2141,"depth":183,"text":2142},{"id":2212,"depth":183,"text":2213},{"id":2252,"depth":183,"text":2253},{"id":2568,"depth":183,"text":2569},{"id":2578,"depth":183,"text":2579},{"id":2598,"depth":183,"text":2599},{"id":2704,"depth":130,"text":2705,"children":2799},[2800,2801,2802,2803],{"id":2708,"depth":183,"text":2709},{"id":2731,"depth":183,"text":2732},{"id":2750,"depth":183,"text":2751},{"id":2763,"depth":183,"text":2764},"agent","2026-06-09","班门弄斧一下","md",false,null,"/images/agent-intro.png",{},"/articles/agent-intro",{"title":5,"description":2806},"articles/agent-intro",[2816,6],"AIAgent","p0_OEX3LXu_ExSGwL-iYxFgwIZXcN5rYwKwEcOf4VYk",1781104361417]