公司动态

AI Agent身份系统构建指南:从角色、记忆、权限到工程实践

📅 2026/8/9 20:24:04
AI Agent身份系统构建指南:从角色、记忆、权限到工程实践
1. 项目概述为什么AI Agent需要一个身份最近在折腾AI Agent项目时我发现一个挺有意思的现象很多开发者包括我自己在初期都把精力一股脑地砸在了LLM大语言模型的调用、工具链的集成和Prompt工程上。我们造出来的Agent能力很强能写代码、查天气、订机票看起来无所不能。但用着用着问题就来了——这个Agent是谁它凭什么能执行这个操作它上次帮我处理了一半的文档我换个问法它怎么就不记得上下文了更关键的是如果我想让多个Agent协作或者让同一个Agent在不同场景下扮演不同角色我该怎么管理这背后缺失的就是一个身份系统。你可以把它理解为AI Agent的“身份证”和“个人档案”。没有它Agent就是一个每次对话都“失忆”的、权限模糊的“临时工”有了它Agent才能成为一个有记忆、有边界、可协作、可管理的“正式员工”。今天我就结合自己的踩坑经验手把手带你从零开始为你的AI Agent搭建一套轻量但核心的身份系统。这不是要取代那些复杂的框架而是帮你理解最核心的肌理让你无论用Spring AI、LangChain还是自己裸写都能心里有数。2. 身份系统的核心四要素一个完整的AI Agent身份系统远不止一个名字那么简单。它至少需要包含四个相互关联的核心要素我把它总结为“角色-记忆-权限-凭证”四件套。缺了任何一个Agent的行为都会出现偏差。2.1 角色定义不止于一个名字给Agent起个名字比如“代码助手小A”这只是第一步。真正的角色定义是一份详细的“岗位说明书”。1. 基础身份信息这相当于Agent的身份证基本信息。通常我会用一个简单的JSON结构来定义{ agent_id: code_assistant_001, name: 小A, description: 专注于Python代码审查与优化的AI助手, version: 1.0, creator: 你的名字, created_at: 2024-05-27 }agent_id是全局唯一的用于系统内部识别name是面向用户的友好称呼。这里有个细节agent_id最好采用有意义的命名规则比如[功能]_[环境]_[序列号]方便后期过滤和查找。2. 角色设定与系统提示词这是身份的灵魂直接决定了LLM的“人格”和行为基线。它应该被深度整合到每次调用LLM的System Prompt中。例如对于“代码助手小A”其核心角色设定可能是“你是一位资深Python开发工程师性格严谨、细致。你的核心职责是审查用户提供的Python代码发现其中的潜在bug、性能瓶颈、不符合PEP 8规范之处并提供具体的优化建议。你的回答应专注于技术本身使用专业术语并优先保证代码的正确性与安全性。”注意事项避免角色冲突如果一个Agent被设计为“幽默的聊天伙伴”同时又赋予它“财务数据分析”的职责这两个角色设定在同一个Prompt里可能会让LLM产生精神分裂般的行为。解决方案是为复杂Agent设计多套可切换的角色配置。具体优于抽象“写好代码”是抽象的“遵循PEP 8圈复杂度不超过10单元测试覆盖率需大于80%”是具体的。越具体的设定Agent的行为越可控。2.2 记忆模块让Agent拥有“过去”失忆的Agent是“一次性”的。记忆模块赋予了Agent连续性主要分为两类1. 会话记忆处理单次对话周期内的上下文。简单实现可以使用一个固定长度的队列来保存最近的对话历史消息列表。from collections import deque class SessionMemory: def __init__(self, max_length10): self.memory deque(maxlenmax_length) # 限制长度防止上下文溢出 def add_interaction(self, user_input, agent_response): self.memory.append({user: user_input, agent: agent_response}) def get_context(self): # 将记忆格式化为LLM可理解的上下文字符串 return \n.join([fUser: {m[user]}\nAgent: {m[agent]} for m in self.memory])关键点max_length需要根据所用LLM的上下文窗口长度和Token消耗来权衡。通常保留最近5-10轮对话是性价比比较高的选择。2. 长期记忆/向量记忆用于存储超越会话周期的、需要被长期记住的知识或事实。这通常通过“向量数据库”来实现。场景用户说“记住我最喜欢的编程语言是Python。” 几天后用户问“根据我的喜好推荐个学习方向。” Agent需要从长期记忆中检索出“喜欢Python”这条信息。简易实现思路当需要记忆时将信息如“用户最喜欢Python”通过文本嵌入模型转换为一个高维向量。将这个向量和原始文本一起存入数据库如Chroma、Redis。当需要检索时将当前问题转换为向量并在数据库中搜索最相似的向量召回对应的文本信息注入到本次对话的上下文中。实操心得记忆的存储与召回并非越多越好。无差别地存储所有对话会引入大量噪声且成本高昂。一个实用的策略是让Agent自己或通过一个规则引擎判断某条信息是否值得存入长期记忆例如当用户使用了“记住”、“请保存”等关键词时触发。2.3 权限与边界设定Agent的“行动范围”一个没有权限控制的Agent是危险的。它可能会在你不知情的情况下执行删除文件、发送邮件、调用付费API等操作。权限系统是Agent安全的护栏。1. 工具权限为Agent可用的每一个工具Tool/Function打上权限标签。tools_permissions { “read_file”: [“guest”, “user”, “admin”], “write_file”: [“user”, “admin”], “execute_command”: [“admin”], “send_email”: [“admin”], “query_database”: [“user”, “admin”] }Agent在执行某个工具前必须检查自身当前所属的角色或权限等级是否在工具允许的列表中。2. 数据访问权限定义Agent可以访问哪些数据源或数据范围。例如“客服Agent”只能访问知识库中的公开FAQ和该用户的订单历史。“数据分析Agent”只能访问脱敏后的统计数据库且不能访问用户个人身份信息表。3. 实现一个简单的权限校验中间件在Agent调用工具的流程中插入一个权限校验层。def permission_check_middleware(agent_id, tool_name, context): agent_role get_agent_role(agent_id) # 从身份系统中获取Agent当前角色 allowed_roles tools_permissions.get(tool_name, []) if agent_role not in allowed_roles: raise PermissionError(fAgent {agent_id} with role {agent_role} is not allowed to use tool {tool_name}) # 继续执行工具调用...踩坑记录初期我曾把权限逻辑写在每个工具函数内部导致代码重复且难以维护。后来抽象成统一的中间件不仅清晰而且方便集中审计所有操作日志。2.4 凭证与密钥管理Agent的“钥匙串”当Agent需要调用外部API如发送邮件、访问云存储、查询数据库时就需要相应的凭证API Key, Token, 用户名密码等。明文硬编码在代码中是绝对的安全禁忌。安全存储方案环境变量适用于单机或简单部署。为不同环境开发、测试、生产配置不同的环境变量文件。密钥管理服务如AWS Secrets Manager, Azure Key Vault, HashiCorp Vault。这是生产环境的推荐做法。你的代码中只包含一个指向KMS的客户端逻辑和密钥标识符真正的密钥由KMS动态提供并自动轮转。加密配置文件将加密后的凭证存储在配置文件中运行时用主密钥解密。主密钥本身通过环境变量或硬件安全模块注入。在身份系统中集成凭证在Agent的身份配置文件里不存储密钥本身而是存储一个密钥的引用标识符。{ agent_id: email_assistant_001, credentials_ref: { smtp_server: secret/email/smtp_config, api_key: secret/third_party/api_key_v1 } }当Agent需要调用发送邮件工具时工具函数根据credentials_ref[smtp_server]这个路径去向密钥管理服务请求真实的SMTP配置。这样即使身份配置文件泄露攻击者也无法直接拿到密钥。3. 从零搭建一个轻量级身份系统的实现理论说完了我们动手搭一个。我们将实现一个名为SimpleAgentIdentity的轻量级系统它包含以上核心要素。3.1 系统架构设计我们的系统将包含以下几个核心模块IdentityRegistry身份注册中心单例模式管理所有Agent的身份信息。AgentIdentity身份实体类包含角色、基础记忆、权限标签等。MemoryManager记忆管理器负责会话记忆和与向量数据库的交互。PermissionValidator权限验证器。CredentialProvider凭证提供者抽象层。它们的关系是IdentityRegistry持有多个AgentIdentity。每个AgentIdentity在运行时会由MemoryManager为其提供记忆上下文由PermissionValidator检查其行动由CredentialProvider为其提供所需的密钥。3.2 核心代码实现我们使用Python来演示核心逻辑。第一步定义身份实体# agent_identity.py from dataclasses import dataclass, field from typing import Dict, List, Any, Optional from datetime import datetime dataclass class AgentIdentity: Agent身份实体 agent_id: str # 唯一标识 name: str # 显示名称 description: str role_prompt: str # 系统提示词中关于角色的部分 metadata: Dict[str, Any] field(default_factorydict) # 扩展元数据 permission_tags: List[str] field(default_factorylambda: [default]) # 权限标签 created_at: datetime field(default_factorydatetime.now) # 注意这里不直接存储密钥只存储引用 credential_refs: Dict[str, str] field(default_factorydict) # 如 {openai_api: ref/path/to/key} def has_permission(self, required_tag: str) - bool: 检查是否拥有某个权限标签 return required_tag in self.permission_tags第二步实现身份注册中心# identity_registry.py class IdentityRegistry: 身份注册中心单例 _instance None _identities: Dict[str, AgentIdentity] {} def __new__(cls): if cls._instance is None: cls._instance super(IdentityRegistry, cls).__new__(cls) return cls._instance def register(self, identity: AgentIdentity): if identity.agent_id in self._identities: raise ValueError(fAgent ID {identity.agent_id} already exists.) self._identities[identity.agent_id] identity print(f[Registry] Agent {identity.name} ({identity.agent_id}) registered.) def get(self, agent_id: str) - Optional[AgentIdentity]: return self._identities.get(agent_id) def list_all(self) - List[AgentIdentity]: return list(self._identities.values())第三步实现记忆管理器# memory_manager.py from collections import deque from typing import Deque, Tuple class SessionMemory: 会话记忆 def __init__(self, maxlen: int 20): self.memory: Deque[Tuple[str, str]] deque(maxlenmaxlen) # (user, agent) 对 def add(self, user_message: str, agent_response: str): self.memory.append((user_message, agent_response)) def get_formatted_context(self, num_turns: int 10) - str: 获取最近N轮对话的格式化上下文 recent list(self.memory)[-num_turns:] context_lines [] for user_msg, agent_msg in recent: context_lines.append(fUser: {user_msg}) context_lines.append(fAssistant: {agent_msg}) return \n.join(context_lines) class MemoryManager: 记忆管理器可扩展长期记忆接口 def __init__(self): self.session_memories: Dict[str, SessionMemory] {} # agent_id - SessionMemory def get_or_create_session(self, agent_id: str) - SessionMemory: if agent_id not in self.session_memories: self.session_memories[agent_id] SessionMemory() return self.session_memories[agent_id]第四步组装并测试# main_demo.py from agent_identity import AgentIdentity from identity_registry import IdentityRegistry from memory_manager import MemoryManager def main(): # 1. 初始化组件 registry IdentityRegistry() memory_mgr MemoryManager() # 2. 创建并注册一个代码助手Agent的身份 code_assistant AgentIdentity( agent_iddev_py_assistant_v1, namePyHelper, descriptionA Python code review assistant., role_promptYou are a meticulous Python expert. Your task is to review code, find bugs, performance issues, and style violations against PEP 8. Provide concise, actionable suggestions., permission_tags[code_read, code_comment, default], credential_refs{openai: secrets/openai/api_key_prod} ) registry.register(code_assistant) # 3. 模拟对话使用记忆 session_memory memory_mgr.get_or_create_session(code_assistant.agent_id) session_memory.add(Check this code: print(Hello, World), The code works. For better practice, consider using a main guard: if __name__ __main__: print(Hello, World)) session_memory.add(What about x 10 / 0?, This will cause a ZeroDivisionError. You should add error handling using try-except.) # 4. 获取对话上下文准备发送给LLM context_for_llm session_memory.get_formatted_context() full_prompt f{code_assistant.role_prompt}\n\nPrevious conversation:\n{context_for_llm}\n\nNew user question: How to handle file not found? print( Prompt to LLM ) print(full_prompt[:500] ...) # 打印前500字符示意 # 5. 权限检查示例 if code_assistant.has_permission(code_read): print(f\nAgent {code_assistant.name} has permission to read code.) else: print(fPermission denied for code_read.) if __name__ __main__: main()运行这个Demo你会看到身份被注册记忆被累积并生成了一个包含角色设定和历史上下文的完整Prompt。权限检查也集成其中。4. 与现有框架的集成实践自己造轮子有助于理解原理但在实际项目中我们更倾向于集成成熟的框架。下面看看如何在LangChain和Spring AI中融入身份概念。4.1 在LangChain中注入身份LangChain的核心是Chain和Agent。我们可以通过自定义BaseMemory和修改AgentExecutor的初始化过程来融入身份。1. 创建带身份标识的CustomMemoryfrom langchain.memory import BaseMemory from typing import Dict, List, Any # 假设我们使用之前实现的MemoryManager from your_identity_system.memory_manager import MemoryManager class IdentityAwareMemory(BaseMemory): LangChain记忆类与我们的身份系统对接 def __init__(self, agent_id: str, memory_manager: MemoryManager): self.agent_id agent_id self.memory_manager memory_manager self.session_memory memory_manager.get_or_create_session(agent_id) property def memory_variables(self) - List[str]: return [chat_history] def load_memory_variables(self, inputs: Dict[str, Any]) - Dict[str, Any]: # 返回格式化后的历史记录 context self.session_memory.get_formatted_context() return {chat_history: context} def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, Any]) - None: user_input inputs.get(input, inputs.get(question, )) # 根据你的Chain输入键调整 agent_output outputs.get(output, outputs.get(text, )) if user_input and agent_output: self.session_memory.add(user_input, agent_output)2. 在构建Agent时绑定身份与记忆from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_openai import ChatOpenAI from langchain.memory import ConversationBufferMemory # 假设你已经定义好了工具和Prompt def create_agent_with_identity(agent_identity: AgentIdentity, tools, prompt): # 1. 初始化LLM可以从身份系统的凭证引用中获取API Key # (实际应从CredentialProvider动态获取此处简化) llm ChatOpenAI(modelgpt-4, temperature0) # 2. 创建身份感知的记忆体 memory_manager MemoryManager() # 应该是全局或注入的单例 identity_memory IdentityAwareMemory(agent_idagent_identity.agent_id, memory_managermemory_manager) # 3. 将角色提示词合并到系统消息中 # 假设你的prompt.template中包含{system_message}占位符 full_system_message f{agent_identity.role_prompt}\n\nYou must adhere to your permissions: {agent_identity.permission_tags} final_prompt prompt.partial(system_messagefull_system_message) # 4. 创建Agent agent create_openai_tools_agent(llm, tools, final_prompt) # 5. 创建执行器并传入记忆 agent_executor AgentExecutor( agentagent, toolstools, memoryidentity_memory, # 关键使用自定义记忆 verboseTrue, handle_parsing_errorsTrue ) return agent_executor这样每次Agent执行时都会自动携带其身份对应的记忆和角色设定。4.2 在Spring AI中实现身份感知Spring AI通过ChatClient和Prompt等抽象进行操作。身份系统可以很好地与Spring的依赖注入和AOP思想结合。1. 定义身份实体Bean与存储Component public class AgentIdentity { private String agentId; private String name; private String rolePrompt; private ListString permissions; private MapString, String credentialRefs; // ... getters, setters, constructors } Repository public class InMemoryIdentityRegistry { private MapString, AgentIdentity registry new ConcurrentHashMap(); public void register(AgentIdentity identity) { ... } public AgentIdentity get(String agentId) { ... } }2. 实现一个身份感知的ChatClient拦截器这是核心我们通过一个ClientInterceptor在请求前后插入身份逻辑。Component public class IdentityAwareInterceptor implements ClientInterceptor { Autowired private IdentityRegistry identityRegistry; Autowired private MemoryService memoryService; // 你的记忆服务 Override public ChatResponse intercept(ChatRequest request, Chain chain) { // 1. 从请求上下文中获取Agent ID (可通过ThreadLocal或请求头传递) String agentId RequestContextHolder.getAgentId(); // 假设有这样一个工具类 AgentIdentity identity identityRegistry.get(agentId); if (identity null) { throw new RuntimeException(Unauthorized or unknown agent: agentId); } // 2. 获取该Agent的历史记忆并添加到本次请求的Prompt中 ListMessage history memoryService.getSessionHistory(agentId); Prompt originalPrompt request.getPrompt(); // 假设request能拿到Prompt // 构建包含角色和历史的系统消息 SystemPromptTemplate systemPrompt new SystemPromptTemplate( {role}\n\nConversation History:\n{history}\n\nCurrent instruction: {instruction} ); Message systemMessage systemPrompt.createMessage( Map.of( role, identity.getRolePrompt(), history, formatHistory(history), instruction, originalPrompt.getContents() // 获取用户当前消息 ) ); // 3. 组装新的Prompt请求 ListMessage messages new ArrayList(); messages.add(systemMessage); // 也可以把历史对话作为User/Assistant消息追加进来... Prompt newPrompt new Prompt(messages); // 4. 创建新请求继续执行 ChatRequest newRequest new ChatRequest(newPrompt, request.getOptions()); ChatResponse response chain.next(newRequest); // 5. 将本次交互保存到记忆 memoryService.saveInteraction(agentId, originalPrompt.getContents(), response.getOutput()); return response; } }3. 配置并使用拦截器Configuration public class AiConfig { Bean public ChatClient chatClient(IdentityAwareInterceptor interceptor) { return ChatClient.builder() .baseUrl(https://api.openai.com/v1) .defaultModel(gpt-4) .interceptor(interceptor) // 注册拦截器 .build(); } }这样所有通过这个ChatClient发出的请求都会自动经过身份和记忆的处理层无需在每个业务代码中重复编写。5. 生产环境进阶考量与避坑指南当你的Agent身份系统从Demo走向生产以下几个问题是必须面对的。5.1 身份的生命周期管理创建与注册应有严格的审批或自动化流程。避免随意创建高权限Agent身份。更新与版本控制当Agent的角色提示词、权限或凭证需要变更时是创建新身份新ID还是更新现有身份我建议采用不可变身份理念重要的变更如角色大改、权限提升应创建新版本的身份如agent_v2并逐步将流量迁移过来。这便于回滚和审计。停用与归档不再使用的Agent身份应及时停用如将状态置为inactive并在一段保留期后归档其记忆数据。切勿直接删除以备审计之需。5.2 记忆的持久化、成本与隐私存储选择会话记忆对延迟敏感数据量小可存放在Redis等内存数据库中。长期记忆向量数据量大检索要求高需要使用专业的向量数据库如Pinecone, Weaviate, Qdrant或支持向量的云数据库如PGVector。成本控制向量存储和检索是按量计费的。务必设置记忆的自动过期策略TTL。例如客服对话记忆保留30天代码审查记忆保留7天。同时在存入长期记忆前通过一个分类器过滤掉无意义的闲聊内容。隐私合规这是红线。身份系统必须能记录哪些数据被哪个Agent在什么时间访问了。如果记忆模块存储了用户个人信息如地址、电话必须进行脱敏处理如替换为[PHONE]标记或确保其符合GDPR等数据保护法规并提供用户数据擦除的接口。5.3 权限模型的细化基础的标签式权限可能很快就不够用了。考虑引入更灵活的模型RBAC基于角色的访问控制将权限分配给角色如reviewer,admin再将角色分配给Agent身份。ABAC基于属性的访问控制根据Agent的属性如所属部门、创建时间、资源的属性、环境属性如时间、地点来动态决定是否允许操作。例如“只有工作时间内且来自内部网络的‘财务分析Agent’才能访问敏感报表。” ABAC更强大但实现也更复杂。5.4 监控、审计与可观测性一个黑盒的身份系统是运维的噩梦。必须建设完善的监控体系日志记录记录所有关键事件。INFO身份创建、注册、权限变更。WARN权限校验失败、凭证获取失败。AUDIT必须记录所有敏感操作如访问用户数据、执行写操作、调用外部付费API等。日志应包含agent_id,user_id,action,resource,timestamp,result。度量指标agent_identity_count活跃身份总数。permission_denied_total权限拒绝次数突增可能意味着攻击或配置错误。memory_usage_bytes各Agent记忆存储量用于成本分析。credential_cache_hit_rate凭证缓存命中率评估性能。分布式追踪在微服务架构下一个用户请求可能触发多个Agent协作。使用OpenTelemetry等工具在追踪链中注入agent_id可以清晰看到整个调用链路中每个Agent的贡献和耗时。5.5 常见陷阱与解决方案陷阱一身份信息泄露在Prompt中导致越权现象在构造Prompt时不小心将其他Agent的对话历史或敏感身份信息混入了当前Prompt。解决方案严格隔离不同Agent的记忆存储空间。在从记忆库检索时agent_id必须作为强制查询条件。在代码审查中要特别注意Prompt模板的拼接逻辑。陷阱二记忆污染导致Agent行为异常现象Agent突然开始说奇怪的话或执行错误操作可能是因为长期记忆中混入了低质量或冲突的信息。解决方案实现记忆的“来源”和“置信度”打分。来自权威知识库的信息置信度高来自单次用户对话的信息置信度低。定期运行“记忆清理”任务根据置信度、时间、使用频率等维度清理或降级低质量记忆。为Agent提供“忘记”指令允许用户手动删除错误的记忆。陷阱三凭证轮转导致服务中断现象定期轮转API Key是安全最佳实践但轮转后所有使用该Key的Agent立刻全部失效。解决方案使用密钥引用而非密钥本身如前所述Agent配置里只存引用路径。实现优雅的凭证刷新CredentialProvider在发现密钥失效时应能自动从KMS获取新密钥并更新本地缓存。对于无法自动刷新的情况如OAuth Token应提前告警。双密钥支持在轮转窗口期内让系统同时支持新旧两个密钥逐步迁移。陷阱四权限膨胀现象为了方便给Agent授予了它“可能”需要的所有权限admin。解决方案严格遵守最小权限原则。初始只授予必要权限。当Agent因权限不足执行失败时系统应记录详细的日志并由管理员审查后再决定是否按需、临时地提升其权限。可以建立一个权限申请-审批流程。为AI Agent构建身份系统看似增加了前期的复杂性但它带来的收益是长期的可控、可信、可协作的智能体。这套系统是你的Agent从玩具走向工具从单点突破走向规模应用的基础设施。