从确定性编程到概率性编程:Agent开发中的上下文工程实践 1. 从.NET到Python一次Agent开发者的认知跃迁如果你和我一样是从.NET、Java这类企业级后端开发领域摸爬滚打过来的第一次接触“Agent开发”这个概念时大概率会感到一种熟悉的陌生感。我们习惯了处理HTTP请求、操作数据库、设计微服务架构脑子里装的是SOLID原则、设计模式和性能优化。当看到“Agent”这个词再结合“LLM”、“上下文”这些热词很容易下意识地把它归类为又一个需要学习的新框架或新库就像当年从WebForms转到ASP.NET Core MVC一样无非是换一套API和编程范式。但经过一段时间的实践和踩坑我得出了一个可能颠覆你认知的结论Agent开发的本质远非学习一个新框架那么简单。它的核心是一场从“确定性编程”到“概率性编程”的思维范式转换。而这场转换的枢纽就是“投喂上下文”。这听起来有点玄乎但请允许我用我们熟悉的.NET世界来打个比方。在传统的Web API开发中我们写一个GetUserById(int id)方法输入是确定的id业务逻辑是确定的数据库查询和映射输出也是确定的User对象。整个流程就像一条精心设计的、没有岔路的管道。而Agent开发更像是你在训练一个非常聪明但经验不足的实习生LLM。你不能只给他一个id就说“去把用户信息拿来”。你需要为他准备好一切用户的数据库表结构是什么样子、我们的UserService类在哪里、调用GetUser方法需要什么权限、甚至之前处理类似请求时留下的成功案例和错误日志。你给他的这一整套“工作手册”和“参考资料”就是上下文Context。所以从.NET转向Python做Agent开发语言和语法是最微不足道的障碍。真正的挑战在于你是否能跳出编写“确定性指令”的舒适区学会如何为LLM这个“非确定性”的黑盒精心编排和投喂高质量的上下文信息引导它产出稳定、可靠的结果。这就是本篇想和你深入探讨的核心。2. 拆解Agent它不是什么以及它到底是什么在深入“上下文”之前我们必须先统一对“Agent”的认识。网络上很多文章把Agent描绘得无所不能导致这个概念被严重泛化和误解。作为一名有工程背景的开发者我们必须先做减法厘清边界。2.1 Agent不是“另一个后端服务”这是最常见的误解。我们很容易把Agent想象成一个升级版的、接入了AI的微服务。你发送请求它返回结果。但在传统微服务中服务的内部逻辑是完全由你编写的代码控制的。而在Agent中核心的“思考”和“决策”过程是由LLM完成的这是一个你无法逐行调试的“概率模型”。你的代码用Python或任何语言所做的工作更多是编排Orchestration准备问题、收集工具、管理上下文、解析LLM的响应并执行下一步。Agent框架如LangChain、LangGraph的本质是提供了一套用于这种编排的标准化模式和工具链而不是替代LLM本身。2.2 Agent的经典架构感知、规划、执行、反思虽然具体实现千差万别但一个典型的Agent循环通常包含以下几个阶段这与我们熟知的“提示词工程、上下文工程、驾驭工程、循环工程”等热词是高度对应的感知/提示词工程Perception/Prompt Engineering这是起点。你需要将用户的目标如“帮我分析上个月的销售数据”转化成一个LLM能理解的初始提示Prompt。这不仅仅是简单的翻译而是需要设定Agent的角色、目标、以及可用的资源边界。例如“你是一个数据分析助手目标是生成一份销售报告。你可以使用query_sales_database工具来获取数据使用generate_chart工具来绘图。”规划/上下文工程Planning/Context Engineering这是最核心、最体现工程师价值的环节。LLM基于初始提示可能会提出一个计划“我需要先查询数据然后按地区汇总最后生成柱状图”。为了让它能制定出合理计划并执行你必须为它提供充足的上下文。这包括工具Tools的描述每个工具叫什么名字输入参数是什么格式JSON Schema这个工具具体是干什么用的你需要用自然语言清晰定义就像给实习生写工具说明书。历史对话Memory当前对话之前说了什么这对于多轮对话至关重要否则Agent就是“金鱼记忆”。领域知识Knowledge相关的产品文档、API说明、代码片段。你可以通过检索增强生成RAG技术动态地将最相关的知识片段插入上下文。执行范例Few-shot Examples提供几个“用户提问-Agent思考过程-最终行动”的完整例子让LLM通过类比学习。这个阶段你的工作就是当一个“图书管理员”和“教练”把LLM完成任务可能需要用到的所有“参考资料”上下文高效、精准地组织好并放在它面前。执行/驾驭工程Action/SteeringLLM根据当前上下文包含了目标、工具、历史、知识输出一个结构化的决策通常是“调用某个工具”或“直接给出最终答案”。你的代码需要解析这个输出安全地调用对应的工具比如执行一段Python函数去查数据库并获取执行结果。反思/循环工程Reflection/Loop Engineering将工具执行的结果成功的数据或错误信息作为新的上下文再次喂给LLM。LLM会评估结果决定是继续下一步行动回到规划阶段还是认为任务已完成可以总结并回复用户。这就构成了一个“思考-行动-观察”的循环。可以看到“上下文”如同血液贯穿了Agent的整个生命周期。每一次与LLM的交互都是一次上下文的投喂。你的编程工作从“编写业务逻辑”变成了“设计和维护一个动态的、高质量的上下文流”。3. 上下文工程详解从理论到实战的“投喂”艺术理解了上下文的核心地位后我们来具体看看在Python的Agent开发中如何实践“上下文工程”。这远比简单地拼接字符串复杂。3.1 上下文的构成不止是聊天记录一个准备投喂给LLM的上下文通常是一个结构化的消息列表。以OpenAI的API为例最常见的格式如下messages [ {role: system, content: 你是一个专业的SQL助手负责将自然语言问题转换为安全、高效的PostgreSQL查询语句。}, # 系统提示设定角色和全局约束 {role: user, content: 找出上个月销售额最高的前10名客户。}, # 用户最新问题 {role: assistant, content: 我需要调用get_table_schema工具来查看客户表和销售表的结构然后才能编写查询。}, # Agent之前的“思考” {role: tool, content: 表customers有字段id, name, region... 表sales有字段sale_id, customer_id, amount, date...}, # 工具调用的结果 {role: assistant, content: 基于表结构我将编写查询SELECT c.name, SUM(s.amount) AS total FROM sales s JOIN customers c ON s.customer_id c.id WHERE s.date 2023-10-01 GROUP BY c.id, c.name ORDER BY total DESC LIMIT 10;}, # Agent基于工具结果给出的回答 ]每一轮新的交互你都需要根据最新的对话状态重新构建或更新这个messages列表然后发送给LLM获取下一步的响应。管理这个列表的状态就是上下文管理的核心。3.2 关键挑战与解决方案长度、相关性与结构直接操作这个列表会遇到几个工程上的大坑挑战一上下文长度限制Context Window所有LLM都有输入长度上限如128K tokens。你不能无限制地堆积历史对话和文档。解决方案包括摘要压缩Summarization将冗长的历史对话总结成一段精炼的文字。例如将十轮关于bug修复的讨论总结为“用户报告了登录接口在并发下偶发500错误已尝试重启服务无效正在排查数据库连接池。”滑动窗口Sliding Window只保留最近N轮对话丢弃更早的。简单但可能丢失重要长期信息。选择性记忆Selective Memory像LangChain提供的EntityMemory会自动提取对话中提到的实体如人名、产品名、订单号并单独存储需要时再召回而非存储全部原始文本。挑战二信息相关性Relevance把一整本产品手册都塞进上下文不仅浪费token还会引入噪声干扰LLM判断。解决方案是检索增强生成RAG。将你的知识库文档、API spec、代码分割成小块chunks并转换为向量embeddings存入向量数据库。当用户提问时将问题也转换为向量在向量数据库中搜索最相关的几个知识块。只将这几个最相关的知识块作为上下文插入提示中。这就实现了“按需投喂”极大提升了效率和质量。挑战三结构化与工具调用Structured Output Tool Calling早期让LLM使用工具非常麻烦需要让它输出“调用工具A参数是{...}”这样的自由文本然后你用正则表达式去解析极易出错。现在主流LLM如GPT-4, Claude都支持了结构化输出JSON Mode和原生工具调用Function Calling。 你可以在上下文中以标准的JSON Schema格式定义好工具列表。LLM会输出一个结构化的JSON对象指明它想调用哪个工具以及参数是什么。你的代码只需反序列化这个JSON即可安全调用。这大大降低了工程复杂度是Agent开发得以普及的关键。# 定义工具的Schema这本身就是一种重要的上下文 tools [ { type: function, function: { name: get_current_weather, description: 获取指定城市的当前天气, # 给LLM看的工具描述 parameters: { type: object, properties: { location: { type: string, description: 城市名称例如北京上海 } }, required: [location] } } } ] # 当LLM决定调用此工具时它会返回一个清晰的JSON而不是一段需要解析的自然语言。4. 实战构建一个简单的数据分析Agent让我们抛开复杂的框架用最朴素的Python代码结合OpenAI API实现一个具备“思考-行动”循环的简易数据分析Agent来感受上下文是如何流动的。假设我们有一个简单的工具query_database(sql_query)它可以执行SQL并返回结果。import openai import json # 模拟的数据库查询工具 def query_database(sql_query: str) - str: # 这里应该是真实的数据库连接和查询 # 为了演示我们返回模拟数据 if sales in sql_query.lower(): return json.dumps([{region: North, amount: 10000}, {region: South, amount: 15000}]) return [] # Agent的核心循环函数 def run_agent(user_query: str, conversation_history: list) - tuple: 运行一轮Agent循环。 返回(Agent的回复文本, 更新后的对话历史) # 1. 构建系统提示和工具定义上下文 system_message { role: system, content: 你是一个数据分析AI助手。你可以通过调用query_database工具来执行SQL查询以获取数据来回答用户问题。工具调用结果将以字符串形式返回给你。请根据结果进行思考并给出最终答案。如果你需要多次查询请逐步进行。 } tools_definition [{ type: function, function: { name: query_database, description: 执行一个SQL查询语句并返回结果。, parameters: { type: object, properties: { sql_query: {type: string, description: 要执行的SQL查询语句} }, required: [sql_query] } } }] # 2. 组装完整的消息上下文系统指令 历史对话 用户新问题 messages [system_message] conversation_history [{role: user, content: user_query}] # 3. 第一次调用LLM期待它可能提出工具调用 response openai.chat.completions.create( modelgpt-4, messagesmessages, toolstools_definition, tool_choiceauto, # 让LLM自行决定是否调用工具 ) response_message response.choices[0].message messages.append(response_message) # 将LLM的响应也加入历史 # 4. 检查LLM是否想要调用工具 tool_calls response_message.tool_calls if tool_calls: # 5. 执行工具调用 for tool_call in tool_calls: function_name tool_call.function.name function_args json.loads(tool_call.function.arguments) if function_name query_database: sql function_args[sql_query] print(fAgent决定执行查询: {sql}) # 日志方便调试 tool_result query_database(sql) # 6. 将工具执行的结果作为新的上下文投喂回去 messages.append({ role: tool, tool_call_id: tool_call.id, content: tool_result, }) # 7. 第二次调用LLM让它基于工具结果进行总结回答 second_response openai.chat.completions.create( modelgpt-4, messagesmessages, ) final_reply second_response.choices[0].message.content messages.append({role: assistant, content: final_reply}) else: # LLM没有调用工具直接给出了答案 final_reply response_message.content messages.append({role: assistant, content: final_reply}) # 返回最终答案和更新后的完整历史用于下一轮对话 return final_reply, messages # 模拟对话 if __name__ __main__: history [] # 初始对话历史为空 user_question 请告诉我北部和南部地区的销售总额分别是多少 reply, updated_history run_agent(user_question, history) print(Agent回复:, reply) print(\n--- 完整的上下文历史用于下一轮---) # 这里可以只保留最近几轮或进行摘要以管理长度在这个简单的例子中你可以清晰地看到上下文messages列表是如何随着对话推进而动态增长的初始[系统指令 用户问题]LLM响应后[... LLM的思考包含工具调用请求]执行工具后[... 工具执行结果]LLM再次响应后[... LLM的最终回答]这个不断膨胀的列表就是Agent的“记忆”和“思考素材”。你的工程挑战在于如何高效、精准地维护它。5. .NET开发者转型Python Agent的实操心法与避坑指南作为一名前.NET开发者在进入Python Agent领域时除了学习Python语法更需要在思维和工具链上进行调整。5.1 思维转换从控制到引导.NET思维全盘控制。异常处理、事务边界、性能瓶颈你都能在代码中精确掌控和追踪。Agent思维引导与容错。你无法控制LLM内部的“思考”只能通过设计更好的上下文提示词、工具描述、示例来提高其输出质量的概率。必须假设LLM可能会“犯错”输出错误格式、调用错误工具因此你的编排代码必须有强大的容错和重试机制。例如当LLM返回的JSON无法解析时不是直接抛异常给用户而是将错误信息作为新上下文反馈给它“你返回的JSON格式有误请重试。”5.2 工具链与调试截然不同的体验开发环境告别Visual Studio的强力IDE拥抱VSCode Jupyter Notebook。Notebook是探索Agent行为的绝佳场所可以分步执行、随时查看中间变量如当前的messages列表直观理解上下文流。调试最痛苦的环节之一。你无法在LLM内部设断点。核心调试手段是日志记录。必须详细记录每一轮投喂给LLM的完整上下文、LLM的原始响应、工具调用的输入输出。当Agent行为异常时回顾这些日志是定位问题的唯一途径。可以借助langsmith、promptfoo等专门针对LLM应用的可观测性平台。测试单元测试变得复杂。你需要模拟LLM的响应。可以使用像pytest配合unittest.mock来模拟openai.ChatCompletion.create的返回值构造各种边界用例如工具调用格式错误、LLM拒绝回答等来测试你的编排逻辑是否健壮。5.3 性能与成本必须考虑的工程约束延迟每次LLM调用都是网络请求加上可能的工具调用如数据库查询整个Agent循环的延迟可能达到秒级。这对于实时交互场景是挑战。需要考虑异步调用、流式响应、以及将耗时工具调用离线执行等策略。成本LLM API按Token收费。冗长、低效的上下文管理会直接烧钱。务必精简系统提示和工具描述。积极采用RAG避免投喂全文档。对历史对话进行压缩摘要。设置合理的超时和重试策略避免陷入无意义的循环。5.4 安全与合规新的风险点提示注入Prompt Injection用户输入可能包含恶意指令试图覆盖你的系统提示让Agent执行非预期操作。必须在将用户输入放入上下文前进行严格的清洗和过滤。工具调用安全LLM可能会生成有害的SQLDROP TABLE或系统命令。绝不能让LLM拥有直接执行高危操作的权限。所有工具调用必须经过一层“沙箱”或“授权”验证。例如SQL工具只能执行SELECT语句或者必须通过一个参数化查询接口杜绝字符串拼接。6. 进阶上下文工程的模式与框架选择当业务逻辑变复杂后手动管理messages列表会变得非常痛苦。这时就需要框架的帮助。目前主流的选择是LangChain和LangGraph它们提供了更高层次的抽象。LangChain提供了Chain的概念将LLM调用、工具使用、上下文检索等环节链接起来。它内置了丰富的上下文管理模块ConversationBufferMemory,ConversationSummaryMemory等和RAG组件。它的学习曲线相对平缓适合快速搭建标准化的Agent流程。LangGraph基于LangChain但引入了图Graph的概念来定义Agent的工作流。节点Node代表一个步骤如调用LLM、执行工具边Edge代表步骤之间的流转条件。这非常适合描述具有复杂分支、循环、并行执行逻辑的Agent。它让你能以更直观、更可维护的方式编排复杂的上下文流转状态。选择建议如果你的Agent是简单的线性“问答-工具-问答”模式LangChain的AgentExecutor足够用。如果你的业务逻辑涉及多轮决策、状态依赖、分支判断例如一个客服Agent需要先判断用户意图再走不同的处理分支那么LangGraph的图模型会是更强大的工具。从.NET的确定性城堡迈入Python Agent的概率性森林最大的障碍不是语法而是思维。我们不再仅仅是代码的编写者更是上下文的设计师、LLM行为的引导者。每一次API调用都是一次精心的“投喂”。而评价一个Agent开发者水平高下的不再是你写了多少行精妙的算法而是你设计的上下文能否让LLM这个“超级实习生”稳定、可靠、安全地完成你交付的任务。这条路充满未知和挑战但也正是其魅力所在。它要求我们兼具工程师的严谨与架构师的视野这何尝不是一次有趣的职业进化。

相关新闻

最新新闻

乌鲁木齐电子商务专业好学校分享

乌鲁木齐电子商务专业好学校分享

在电商行业蓬勃发展的当下,乌鲁木齐的电商专业学校为众多学子提供了学习电商技能的优质平台。下面就为大家深入分析。一、乌鲁木齐电商人才需求现状行业报告显示,近年来乌鲁木齐电商行业呈现快速增长态势,企业对电商专业人才的需求持续上升。…

2026/8/11 16:26:10
北京燃气灶维修全域覆盖 欧米到家同城上门深度检修承诺不返工|打不着火|松手熄火|黄火冒黑烟|漏气|各类故障一站式解决

北京燃气灶维修全域覆盖 欧米到家同城上门深度检修承诺不返工|打不着火|松手熄火|黄火冒黑烟|漏气|各类故障一站式解决

导读北京燃气灶出现打不着火、点火后松手熄火、火焰发黄、冒黑烟、燃烧不均、旋钮失灵或疑似漏气等问题,可联系欧米到家统一报修热线400-996-9791。平台根据所在区域安排同城维修师傅上门,先检测故障原因,再说明维修方案和费用,确…

2026/8/11 16:26:10
Jenkins基本使用教程

Jenkins基本使用教程

下载地址:Jenkins 的安装和设置 1.创建任务 (需下载maven插件) 2.配置git凭证 (需下载git插件) 3.配置 git参数,使在构建时可选分支 4.配置仓库地址,默认分支 5.配置前置脚本 6.配置后置脚本

2026/8/11 16:26:10
RAID磁盘阵列分析,超详细

RAID磁盘阵列分析,超详细

目录 前言 一、Raid介绍 1、什么是Raid 2、Raid作用 二、raid冗余磁盘阵列的优缺点 1、Raid 0 2、Raid 1 3、Raid5 4、Raid6 5、Raid10 三、Raid5与Raid10哪个好? 1、安全性方面的比较 2、空间利用率的比较 3、读写性能方面的比较 4、特殊情况下&#…

2026/8/11 16:26:10
鸿蒙 DevEco Testing:性能测试(三)

鸿蒙 DevEco Testing:性能测试(三)

一、质量测试 基于应用性能测试标准,提供一套包含智能遍历算法和性能指标分析,用于评估应用性能。通过模拟用户操作行为,对应用进行长时间、高频次的页面遍历,实时采集性能数据,生成全面、专业的测试报告。 质量测试…

2026/8/11 16:26:10
WXEntryActivity无返回

WXEntryActivity无返回

在实现微信登录出现微信已经授权但是无返回结果的情况,查看logcat出现空指针com.tencent.mm E/System: java.lang.NullPointerException: Attempt to invoke virtual method void java.nio.channels.FileLock.release() on a null object reference解决方法WXEntryA…

2026/8/11 16:21:10