1. 项目概述一个面向LLM应用开发的模块化工具箱如果你正在尝试构建基于大语言模型的应用无论是想做一个能自动处理邮件的智能助手还是一个能分析文档并生成报告的系统你大概率会面临一个共同的起点从零开始。这意味着你需要自己设计系统提示词、编写工具调用逻辑、规划智能体的工作流这个过程充满了重复造轮子的低效和不确定性。今天要聊的这个项目llm_system_template_agents_skills_patterns_tools_prompts正是为了解决这个痛点而生。它不是一个成品应用而是一个高度模块化的“工具箱”或“脚手架”为你提供了一套经过验证的、可复用的组件库让你能像搭积木一样快速构建起自己的LLM应用。这个项目的核心价值在于“解耦”和“组合”。它将一个复杂的LLM系统拆解为几个清晰的层次系统提示词定义了AI的“角色”和基础行为准则工具赋予了AI调用外部API或执行特定函数的能力技能是更复杂的、可复用的任务单元智能体则负责协调这些组件来完成一个完整的目标而模式则是解决某一类问题的标准化工作流模板。这种设计思想对于任何希望提升开发效率、保证代码质量、并追求架构清晰的开发者来说都极具吸引力。无论你是刚接触LLM编程的新手还是正在为团队寻找标准化方案的资深工程师这个项目提供的模板和模式都能为你节省大量前期调研和基础编码的时间。2. 核心架构与设计模式深度解析2.1 分层架构从原子工具到智能工作流理解这个项目的关键在于把握其清晰的分层架构。这并非简单的代码堆积而是一种经过深思熟虑的、旨在降低复杂性的设计。我们可以将其类比为建造一栋房子工具是砖块和木材技能是预制好的门窗和楼梯模式是客厅或厨房的标准设计图而智能体则是统筹整个建造过程的项目经理。工具层是最基础的原子操作。一个工具通常对应一个具体的函数或API调用例如“获取当前天气”、“搜索网络信息”、“读写本地文件”。在项目中这些工具被标准化封装确保它们有统一的输入输出接口便于被上层组件调用。技能层则构建在工具之上它代表了一个完整的、可复用的任务。例如“总结一篇长文章”这个技能内部可能依次调用了“读取文件”、“调用LLM总结”、“保存结果”等多个工具。技能封装了实现细节对外提供更高级、更语义化的接口。模式层是该项目最具特色的部分。它借鉴了软件工程中“设计模式”的思想针对LLM应用中的常见场景提炼出可复用的解决方案模板。例如“问答模式”可能定义了一个标准的流程接收用户问题 - 检索相关知识库 - 组织答案 - 安全审查 - 返回结果。直接套用这些模式开发者就无需重新设计工作流只需填充具体的实现细节如自己的知识库接口。智能体层是最高级的协调者。一个智能体可以理解复杂目标并动态地组合调用多个技能、工具或遵循某个模式来完成任务。例如一个“研究助手”智能体在接到“分析某个技术趋势”的任务后可能会自动触发“网络搜索”技能获取资料再用“多文档总结”模式提炼核心观点最后调用“生成报告”技能输出结果。2.2 设计原则可组合性、数据主权与供应商中立这个项目的设计背后贯穿着几个关键的软件工程原则这也是它区别于许多一次性脚本或封闭框架的地方。可组合性是第一要义。所有组件都设计为高内聚、低耦合的模块。这意味着你可以轻松地将项目中的“天气查询工具”与你自定义的“出行规划技能”组合而无需修改工具的内部代码。这种设计极大地提升了代码的复用率和系统的灵活性。数据主权是一个在AI时代愈发重要的考量。该项目强调避免将用户数据锁定在某个特定的云服务或厂商生态中。它的模板和模式鼓励你将核心逻辑、数据处理流程掌握在自己手中而将LLM API如OpenAI、Anthropic的Claude、或本地模型视为一个可替换的“计算资源”。这通过清晰的接口抽象来实现例如定义一个统一的“LLM调用器”接口背后可以轻松切换不同的模型提供商。供应商中立原则与数据主权相辅相成。项目没有深度绑定任何一家商业LLM服务。它提供的提示词模板、工具调用规范都是通用的你可以将其用于Claude Code、GitHub Copilot的底层模型或是任何兼容OpenAI API格式的本地模型如通过Ollama部署的。这种中立性保障了项目的长期生命力和你的技术选型自由。提示词工程系统化是该项目的另一大贡献。它没有将提示词视为散落在代码各处的魔法字符串而是将其作为一等公民进行管理。提示词被模板化、参数化甚至版本化。例如一个“代码审查”提示词模板可能包含占位符{code}和{language}在实际调用时被具体值替换。这种管理方式使得提示词的迭代、优化和团队协作变得可行且高效。3. 核心组件详解与实操配置3.1 提示词模板库超越简单文本替换很多人认为提示词就是一段写给AI的指令。但在这个项目中提示词模板被提升到了“系统配置”的高度。它通常是一个包含角色定义、任务描述、输出格式约束、以及少样本示例的结构化文本。一个典型的系统提示词模板可能如下所示以Markdown格式存储# 角色 你是一个资深的{domain}专家擅长以清晰、结构化的方式分析和解决问题。 # 任务 用户将提供一个关于{task_topic}的请求。你的目标是 1. 首先理解用户的核心需求。 2. 然后遵循{procedure}的步骤进行分析。 3. 最后将你的分析结果以{output_format}的格式呈现。 # 约束 - 思考过程请放在thinking标签内。 - 最终答案请放在answer标签内。 - 如果信息不足请明确询问不要猜测。 # 示例 用户帮我分析这段Python代码的复杂度。 thinking用户需求是代码复杂度分析。我需要使用大O表示法分析循环和递归... /thinking answer时间复杂度为O(n^2)因为存在嵌套循环。空间复杂度为O(1)。/answer在实际使用时系统会通过模板引擎如Jinja2将{domain}、{task_topic}等变量替换为具体的值如“软件工程”、“性能优化”从而动态生成精准的提示词。项目库中预置了大量此类模板覆盖了代码生成、文本总结、数据分析、创意写作等多个场景。实操心得不要直接硬编码提示词。利用项目的模板系统将可变的因素参数化。这样当你需要调整AI的角色或任务时只需修改模板文件或传入不同的参数而无需搜索和替换代码中的多个字符串极大减少了出错概率。3.2 工具与技能的实现与注册工具在代码层面通常实现为一个Python函数并使用装饰器或特定基类进行注册以便被框架自动发现和管理。以下是一个简化的工具定义示例# 假设项目使用类似LangChain的装饰器 from llm_system.decorators import tool tool(nameget_weather, description根据城市名称获取当前天气情况) def get_weather(city: str) - str: 调用天气API获取信息。 Args: city: 城市名例如“北京” Returns: 格式化的天气信息字符串 # 这里模拟API调用 # 实际项目中会集成真实的天气API如OpenWeatherMap weather_data call_weather_api(city) return f{city}的天气是{weather_data[condition]}温度{weather_data[temp]}°C。 # 技能则是多个工具和逻辑的组合 from llm_system.skill import Skill class SummarizeDocumentSkill(Skill): name summarize_document description 总结一个长文档的核心内容 def execute(self, document_path: str, summary_length: str medium) - dict: # 1. 调用工具读取文档 content self.invoke_tool(read_file, pathdocument_path) # 2. 根据长度选择提示词模板 prompt_template self.get_prompt(summarize, lengthsummary_length) prompt prompt_template.render(contentcontent) # 3. 调用工具请求LLM生成总结 summary self.invoke_tool(call_llm, promptprompt) # 4. 返回结构化结果 return { original_file: document_path, summary: summary, length: summary_length }注意事项在定义工具时务必为其提供清晰、准确的name和description。因为智能体尤其是基于LLM的规划型智能体会依赖这些描述来决定在何时调用哪个工具。描述应简明扼要地说明工具的用途、输入和输出。对于技能重点在于设计好其执行流程和错误处理。例如在SummarizeDocumentSkill中如果文件不存在或无法读取应该在调用read_file后进行检查并抛出清晰的异常而不是让流程继续下去导致后续调用失败。3.3 智能体模式与工作流引擎项目中的“模式”通常体现为预定义的工作流或状态机。它们可能以YAML配置文件、Python类或可视化流程图的形式存在。一个用于处理客户支持的“分类-路由-解决”模式可能如下配置# support_ticket_pattern.yaml name: customer_support_triage steps: - name: classify_intent agent: classifier_agent tool: call_llm prompt_template: intent_classification.j2 outputs: [intent, urgency] - name: route_ticket agent: router_agent condition: {{ intent in [billing, technical] }} target_skill: - if: intent billing use: billing_support_skill - if: intent technical use: technical_support_skill default_skill: general_inquiry_skill - name: execute_resolution agent: executor_agent input_from: route_ticket.output skill: {{ selected_skill }}这个YAML定义了一个三步骤的工作流。开发者只需提供具体的classifier_agent、billing_support_skill等实现即可快速获得一个完整的客服工单处理流水线。核心优势在于业务逻辑工作流与实现细节具体的Agent和Skill分离。当你想修改流程时例如在分类后增加一个情感分析步骤只需调整模式配置文件而无需重写大量代码。4. 从零开始搭建你的第一个LLM智能体应用4.1 环境准备与项目初始化假设我们想利用这个模板库快速构建一个“智能技术文档问答助手”。它的功能是用户输入一个技术问题助手能自动搜索相关文档片段并生成一个简洁准确的答案。首先我们需要搭建开发环境。虽然项目文档提到对编程技能要求不高但进行定制化开发仍需基本的Python环境。# 1. 克隆仓库假设你已安装Git git clone https://github.com/zartin790/llm_system_template_agents_skills_patterns_tools_prompts.git cd llm_system_template_agents_skills_patterns_tools_prompts # 2. 创建并激活Python虚拟环境强烈推荐避免包冲突 python -m venv venv # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate # 3. 安装核心依赖 # 项目根目录通常会有requirements.txt或pyproject.toml pip install -r requirements.txt # 4. 安装你所需的额外包例如用于向量数据库和网络搜索的库 pip install chromadb langchain-community duckduckgo-search关键步骤解析使用虚拟环境是Python开发的最佳实践它能将项目的依赖包与系统全局环境隔离。安装的chromadb是一个轻量级向量数据库用于存储和检索文档嵌入duckduckgo-search则提供了一个免费的搜索工具。这些选择基于其易用性和开源免费的特性符合项目“供应商中立”的原则。4.2 构建核心组件检索工具与问答技能接下来我们创建两个核心组件一个从向量数据库检索相关文档的工具和一个整合检索与生成的问答技能。第一步实现检索工具。我们在项目的tools/目录下新建一个文件retrieve_docs_tool.py。# tools/retrieve_docs_tool.py import chromadb from llm_system.decorators import tool # 初始化一个持久的向量数据库客户端 CHROMA_CLIENT chromadb.PersistentClient(path./chroma_db) tool(nameretrieve_technical_docs, description从技术文档库中检索与问题最相关的3个文档片段。) def retrieve_docs(question: str, collection_name: str tech_docs) - list: 基于语义相似度检索文档。 Args: question: 用户的技术问题。 collection_name: 向量数据库集合的名称。 Returns: 一个列表包含检索到的文档片段及其元数据。 try: collection CHROMA_CLIENT.get_collection(namecollection_name) # 进行相似性搜索获取最相关的3个结果 results collection.query( query_texts[question], n_results3 ) # 格式化返回结果 documents [] for i in range(len(results[documents][0])): doc { content: results[documents][0][i], source: results[metadatas][0][i].get(source, unknown), relevance_score: results[distances][0][i] # 注意距离越小越相关 } documents.append(doc) return documents except Exception as e: return [{error: f检索失败: {str(e)}, content: }]第二步创建问答技能。我们在skills/目录下新建answer_tech_question_skill.py。# skills/answer_tech_question_skill.py from llm_system.skill import Skill from llm_system.prompt_manager import PromptManager class AnswerTechQuestionSkill(Skill): name answer_tech_question description 通过检索文档和推理来回答技术问题。 def __init__(self): self.prompt_manager PromptManager() def execute(self, user_question: str) - dict: # 1. 检索相关文档 retrieved_docs self.invoke_tool(retrieve_technical_docs, questionuser_question) # 检查检索是否出错 if retrieved_docs and error in retrieved_docs[0]: return {answer: 抱歉文档检索服务暂时不可用。, sources: []} # 2. 构建上下文 context \n\n--- 参考文档 ---\n for doc in retrieved_docs: context f来自 {doc[source]}:\n{doc[content]}\n\n # 3. 获取并渲染提示词模板 # 假设我们在 prompts/ 目录下有一个 tech_qa.j2 模板文件 prompt_template self.prompt_manager.get_template(tech_qa) final_prompt prompt_template.render( questionuser_question, contextcontext ) # 4. 调用LLM生成答案 llm_response self.invoke_tool(call_llm, promptfinal_prompt, modelgpt-4) # 5. 整理来源信息 sources [doc[source] for doc in retrieved_docs if doc.get(source)] return { question: user_question, answer: llm_response, sources: sources, retrieved_count: len(retrieved_docs) }实操要点在技能中我们通过self.invoke_tool来调用之前注册的工具这实现了组件间的松耦合。PromptManager是项目可能提供的一个辅助类用于加载和渲染Jinja2模板。你需要提前在prompts/tech_qa.j2文件中编写好提示词模板定义AI如何利用问题和上下文生成答案。4.3 装配智能体与主程序入口最后我们将技能装配到一个智能体中并创建主程序来运行它。在agents/目录下创建tech_support_agent.py。# agents/tech_support_agent.py from llm_system.agent import AgentBase from skills.answer_tech_question_skill import AnswerTechQuestionSkill class TechSupportAgent(AgentBase): 技术文档问答智能体 def __init__(self, nameTechDocHelper): super().__init__(name) # 注册该智能体可用的技能 self.register_skill(AnswerTechQuestionSkill()) def run(self, input_data: dict) - dict: 智能体的主要运行逻辑。 Args: input_data: 包含用户问题的字典如 {question: 如何配置Python虚拟环境} user_question input_data.get(question, ) if not user_question: return {error: 未提供问题。} # 调用技能执行核心任务 result self.invoke_skill(answer_tech_question, user_questionuser_question) return result现在创建一个主程序文件main.py来启动一切# main.py import sys from agents.tech_support_agent import TechSupportAgent def main(): # 1. 初始化智能体 agent TechSupportAgent() # 2. 获取用户输入这里简单从命令行参数读取 if len(sys.argv) 1: question .join(sys.argv[1:]) else: question input(请输入您的技术问题: ) # 3. 运行智能体 print(f\n 正在为您查询: {question}) result agent.run({question: question}) # 4. 输出结果 if error in result: print(f❌ 出错: {result[error]}) else: print(f\n 答案: {result[answer]}) if result[sources]: print(f 参考来源: {, .join(result[sources])}) if __name__ __main__: main()运行你的应用python main.py Python中async和await怎么用。智能体会自动触发检索、生成流程并返回答案和来源。至此你已利用模板库的核心思想快速构建了一个具备检索增强生成能力的最小可行产品。5. 高级模式应用与性能调优实战5.1 实现复杂的链式与分支工作流基础技能和智能体能满足简单任务。但对于复杂场景如一个需要多步骤决策的“内容审核”流程就需要用到项目中的“模式”概念。假设流程是先检查文本毒性如果通过则进行事实核查再不通过则进行摘要生成以供人工复审。我们可以将此模式实现为一个工作流类# patterns/content_moderation_pattern.py from enum import Enum from llm_system.pattern import WorkflowPattern class ModerationResult(Enum): APPROVED approved NEEDS_FACT_CHECK needs_fact_check NEEDS_HUMAN_REVIEW needs_human_review class ContentModerationPattern(WorkflowPattern): name content_moderation def execute(self, content: str) - dict: # 步骤1: 毒性检查 toxicity_check self.invoke_skill(toxicity_check, textcontent) if toxicity_check.get(is_toxic, True): # 毒性高直接标记为需人工审核 summary self.invoke_skill(summarize_content, textcontent, reasontoxic_content) return { final_decision: ModerationResult.NEEDS_HUMAN_REVIEW.value, reason: 内容含有不当言论。, summary_for_reviewer: summary } # 步骤2: 事实核查 (仅对非毒性内容) fact_check self.invoke_skill(fact_check_claim, textcontent) if not fact_check.get(is_accurate, False): # 事实存疑也需人工审核 summary self.invoke_skill(summarize_content, textcontent, reasonfactual_dispute) return { final_decision: ModerationResult.NEEDS_HUMAN_REVIEW.value, reason: 事实准确性存疑。, summary_for_reviewer: summary, disputed_points: fact_check.get(disputes, []) } # 步骤3: 所有检查通过 return { final_decision: ModerationResult.APPROVED.value, reason: 内容通过所有自动审核。 }这个模式清晰地定义了业务逻辑流。它的优势在于审核策略先毒检再事实核查被固化在模式中而具体的检查技能toxicity_check,fact_check_claim可以独立开发和替换。例如你可以将基于关键词的毒检升级为基于深度学习模型的毒检而无需修改工作流模式本身。5.2 提示词迭代与性能优化技巧LLM应用的性能和输出质量极大程度上取决于提示词。项目提供的模板是起点而非终点。你需要建立自己的迭代优化流程。A/B测试框架不要凭感觉修改提示词。创建一个简单的测试框架用一批标准问题测试集来评估不同提示词版本的效果。# utils/prompt_ab_test.py import json from agents.tech_support_agent import TechSupportAgent def run_ab_test(prompt_version_a, prompt_version_b, test_questions_file): agent TechSupportAgent() with open(test_questions_file, r) as f: questions json.load(f) results [] for q in questions: # 测试版本A agent.prompt_manager.set_active_version(tech_qa, prompt_version_a) result_a agent.run({question: q}) # 测试版本B agent.prompt_manager.set_active_version(tech_qa, prompt_version_b) result_b agent.run({question: q}) # 这里可以引入人工评估或自动评估指标如答案相关性、准确性打分 # 暂时简单记录答案长度作为粗略对比 results.append({ question: q, answer_a_len: len(result_a.get(answer, )), answer_b_len: len(result_b.get(answer, )) }) return results结构化输出引导为了便于后续程序化处理强烈建议在提示词模板中要求LLM输出结构化数据如JSON。例如在tech_qa.j2模板末尾加上“请以以下JSON格式输出{answer: 你的答案, confidence: 高|中|低, key_points: [点1, 点2]}”。这能显著提升下游系统解析结果的可靠性。上下文管理与长度优化当检索到的文档过多时可能超出LLM的上下文窗口。需要在技能层实现“智能截断”逻辑。不是简单取前N个字符而是根据相关性分数排序并优先保留分数最高的片段同时确保总长度不超过限制。这通常需要在AnswerTechQuestionSkill.execute方法中的“构建上下文”步骤里实现。5.3 系统监控、日志与错误处理一个健壮的生产级应用离不开完善的可观测性。项目模板通常预留了集成点。结构化日志使用Python的logging模块为不同组件设置不同日志级别。import logging # 在技能或工具中 logger logging.getLogger(__name__) class AnswerTechQuestionSkill(Skill): def execute(self, user_question: str) - dict: logger.info(f开始处理问题: {user_question[:50]}...) try: retrieved_docs self.invoke_tool(...) logger.debug(f检索到 {len(retrieved_docs)} 个文档片段。) # ... 后续处理 except Exception as e: logger.error(f技能执行失败问题: {user_question}, 错误: {e}, exc_infoTrue) return {error: 内部处理错误}关键指标收集在关键路径上记录性能指标如工具调用耗时、LLM响应耗时、Token使用量、缓存命中率等。这些数据可以帮助你定位瓶颈。例如你可以用装饰器来包装工具调用函数自动记录其执行时间。优雅降级与熔断对于依赖外部API的工具如LLM调用、搜索必须实现错误处理和降级方案。例如当主要LLM API超时时可以自动切换到备用API或返回一个缓存的通用答案。项目中的工具抽象层是实现这种熔断逻辑的理想位置。6. 常见问题排查与效能提升指南在实际开发和运行中你肯定会遇到各种问题。下面是一些典型问题及其排查思路以及进一步提升系统效能的建议。6.1 典型问题速查表问题现象可能原因排查步骤与解决方案智能体无法找到或调用技能/工具1. 技能/工具未正确注册。2. 名称拼写错误。3. 依赖的模块未导入。1. 检查技能类的name属性与调用时使用的字符串是否完全一致区分大小写。2. 在智能体__init__方法中确认已调用self.register_skill(...)。3. 确保定义工具/技能的Python文件所在的目录已被添加到PYTHONPATH或在主程序中被正确导入。LLM调用返回无关或格式错误的答案1. 提示词模板渲染错误。2. 系统提示词角色定义太弱或冲突。3. 上下文信息过多或杂乱。1. 打印出最终发送给LLM的完整提示词检查变量替换是否正确格式是否清晰。2. 强化系统提示词明确指令如“你必须严格按照JSON格式输出”。3. 实现上文提到的“上下文智能截断”优先保留相关性最高的信息。向量检索结果质量差1. 文档嵌入模型不匹配或质量差。2. 检索参数如n_results设置不合理。3. 文档块切分策略不佳。1. 确保检索时使用的嵌入模型与构建向量数据库时使用的是同一模型系列。2. 调整n_results太小时可能遗漏关键信息太大时可能引入噪声。可以先从5-10开始尝试。3. 检查文档预处理是否按语义段落切分是否保留了必要的上下文如标题应用响应速度慢1. 工具或LLM调用是同步阻塞的。2. 未使用缓存。3. 检索的文档块过大、过多。1. 对于独立的工具调用如多个并行的网络请求考虑使用asyncio或线程池改为异步。2. 为频繁查询且结果变化不大的工具如某些知识检索添加缓存层如使用functools.lru_cache。3. 优化文档切分策略避免单个片段过长在技能逻辑中对检索结果做更严格的过滤。内存使用量持续增长1. 存在全局变量或缓存未及时清理。2. 大对象如加载的模型生命周期管理不当。1. 使用内存分析工具如tracemalloc定位泄漏点。2. 对于大型工具如本地嵌入模型将其设计为可懒加载的单例或在不需要时显式卸载。6.2 效能提升进阶技巧实现工具调用缓存对于纯函数式、输入相同则输出必然相同的工具如某些计算、或对静态数据的查询添加缓存能极大提升性能。from functools import lru_cache from llm_system.decorators import tool tool(namecalculate_md5) lru_cache(maxsize128) # 缓存最近128次调用 def calculate_file_md5(file_path: str) - str: import hashlib # ... 计算MD5的逻辑 return md5_hash设计异步智能体对于I/O密集型应用如需要同时调用多个外部API将智能体和工具改造成异步模式可以大幅减少总等待时间。这需要基于asyncio重构让工具函数返回awaitable对象并在技能中使用await来调用。建立评估与回馈闭环在AnswerTechQuestionSkill的返回结果中可以加入一个feedback_id。在前端界面提供“答案是否有用”的反馈按钮。将用户反馈问题、答案、反馈结果记录到数据库。定期用这些数据微调你的提示词模板或作为评估检索质量的新训练数据。这是让系统持续进化的关键。利用项目的模式库进行重构当你发现自己在多个智能体中重复编写相似的工作流逻辑时例如都是“检索-分析-报告”三步走就是时候考虑将其抽象成一个通用的“检索增强生成模式”了。参考项目中原有的模式实现创建你自己的模式类。这样下一个类似项目就可以直接复用这个模式只需注入不同的检索工具和报告模板即可开发效率成倍提升。