Um SDK do MongoDB Atlas Agent Engine. Fornece um wrapper fino específico do LangChain sobre o tempo de execução da plataforma agent-engine-runner-shared.
Início rápido
Instalação
pip install agent-engine-sdk-langgraph
Ou em um projeto uv:
uv add agent-engine-sdk-langgraph
Agente mínimo
from agent_engine_sdk_langgraph import App from langgraph.graph import StateGraph, MessagesState from langgraph.prebuilt import ToolNode app = App(app_name="my-agent", app_version="1.0.0") def lookup(query: str) -> str: """Search the knowledge base.""" return "result for " + query def build_agent(): from langchain_openai import ChatOpenAI llm = app.llm(ChatOpenAI(model="gpt-5.4")) tools = app.get_tools() def call_model(state: MessagesState): response = llm.invoke(state["messages"]) return {"messages": [response]} graph = StateGraph(MessagesState) graph.add_node("agent", call_model) graph.add_node("tools", ToolNode(tools)) graph.set_entry_point("agent") graph.add_edge("tools", "agent") return graph.compile(checkpointer=app.checkpointer()) app.run()
Usando memória
app.memory é a face unificada `agent-engine-sdk-memory <../agent-engine-sdk-memory/README.md>'__ Memory (limitada à aplicação durante o tempo de execução da plataforma). A identidade é resolvida por chamada do argumento, de um contexto vinculado ou do contexto de execução do ambiente.
app = App(app_name="my-agent") # Save a semantic fact — returns CreateSemanticResult result = app.memory.save_semantic( text="User prefers dark mode", label="pref-theme", user_id="u1", metadata={"channel": "web", "priority": "high"}, # optional caller-supplied metadata ) if result.acknowledged: ... # Search — returns list[MemoryChunk] chunks = app.memory.search_semantic(query="user preferences", user_id="u1") for chunk in chunks: print(chunk.content) # Build prompt context — returns ContextResponse # Default sources are LTM (episodic + semantic); pass # enabled_sources={"stm", ...} to include recent turns. context = app.memory.build_context(query="help me", user_id="u1") prompt_block = context.formatted_context # str (or structured list, depending on format)
build_context_from_sources (modos de recuperação por fonte, filtros e top_k) está disponível no tempo de execução ambiente app.memory. Ele retorna ContextResponse completo, então os metadados por fonte (ranking_strategy, source_outcomes) sobrevivem; a plataforma carimbos de aluguel e carrega a resposta de volta por meio da execução durável. session_id é necessário somente quando a origem stm é solicitada.
from agent_engine_sdk_langgraph import Memory reexporta a mesma classe que agent_engine_sdk_memory.Memory. Construir você mesmo Memory(api_key=...) / Memory(base_url=...) é o caminho HTTP/direto , não vinculado ao aplicativo ambiente.
Quando isso quebra
Este é um corte forçado: não há API dupla e nenhum ajuste de compatibilidade no app.memory. Os agentes do cliente quebram somente quando reconstróem uma imagem do agente que pega as discos da base do executor que contêm esse SDK. A mesclagem de plataformas por si só ou a reimplantação de uma imagem antiga de agente não altera o código do SDK já incorporado a essa imagem. Não há migração de dados de memória armazenada - apenas as formas de retorno do cliente e as convenções de chamada mudam.
Migração da superfície pré-fachada
Tipos de retorno / veracidade / metadados / ``build_context``: grava resultados digitados de retorno (
CreateSemanticResult,CreateEpisodicResultetc.) comacknowledged— não apenasbool/dicts. Prefiraif result.acknowledged:(nãoif result:– os modelos pydentic são sempre verdadeiros). As pesquisas de similaridade retornamlist[MemoryChunk](chunk.content,chunk.similarity_scoreopcional). Campos livres que costumavam ser chaves de dicionário de nível superior (title,summary,tags,term,definition,related_terms, ...) vivem sobchunk.metadata(por exemplo,ep.metadata.get("title")em vez deep.get("title")).build_contextretornaContextResponse; usecontext.formatted_context, não o valor de retorno como uma string.Os ajudantes de gravação são somente palavras-chave (
save_semantic(text=..., label=..., …)). As chamadas posicionais aumentamTypeError.As leituras com ``visibility="private"`` mantêm o filtro de usuário ambiente (anteriormente a aprovação de qualquer argumento
visibilityo descartou): pesquisas de visibilidade privada agora retornam apenas as memória do usuário atual, a menos que umuser_idexplícito seja passado.``top_k``: por fonte
search_semantic/search_episodes/search_taxonomicpadrão paratop_k=50(geralmente era10).discover_proceduresainda é padronizado como10. OMemory.search()unificado ainda tem como padrãotop_k=10. Obuild_contextpúblico não tem nenhum parâmetrotop_k. Usemax_tokenspara um orçamento bruto de construção de contexto (não um custo de busca). Após a recuperação e a classificação, o servidor subtrai uma reserva de formatação de token 500 e, em seguida, seleciona avidamente chunks de memória inteiros que cabem no restante. Valores positivos iguais ou inferiores a 500 não deixam orçamento para recordações. Valores acima de 500 ainda podem gerar um contexto vazio quando nenhum chunk se encaixa. Passe umtop_kexplícito sobre os auxiliares de pesquisa se precisar do limite antigo.Identidade: os campos obrigatórios que não podem ser resolvidos aumentam
MemoryIdentityError(chega deNonesuave / salto silencioso).save_episoderequer umsession_idresolvível (o contexto de invocação do ambiente é adequado; caso contrário, passe-o explicitamente ou vincule umMemoryRequestContext). Os valores em branco não contam como definidos.Fidelidade de criação vinculada ao aplicativo: create-result
idpode ser""ehas_embeddingnormalmenteFalse— sucesso do Gate em.acknowledged, nãoid. Os detalhes por operação estão na matriz de capacidade do pacote de memória.Obtém versus pesquisa:
get_semantic/get_taxonomic_term/list_episodesainda retornam dicionários de tipo livre no limite do aplicativo. Somente os métodossearch*retornamlist[MemoryChunk].Renomeia: se alguém chamou os nomes da pré-fachada, use a API pública da fase —
create_taxonomic→save_taxonomic;list_taxonomic_domains→list_domains.
Antes / depois
# save_semantic: bool → .acknowledged; positional → keyword-only # before ok = app.memory.save_semantic("User prefers dark mode", "pref-theme", user_id="u1") if ok: ... # after result = app.memory.save_semantic( text="User prefers dark mode", label="pref-theme", user_id="u1", ) if result.acknowledged: ...
# save_episode: str|None → CreateEpisodicResult (.acknowledged / .id) # before doc_id = app.memory.save_episode(title="Quote chat", content=summary, user_id="u1") if doc_id: ... # after episode = app.memory.save_episode( title="Quote chat", content=summary, user_id="u1", metadata={"channel": "web", "priority": "high"}, # optional caller-supplied metadata # session_id from ambient context, or pass explicitly ) if episode.acknowledged: print(episode.id) # may be "" on app-bound
# search_episodes: dict.get → MemoryChunk metadata + content; pin top_k if needed # before episodes = app.memory.search_episodes(query="policy quote", top_k=10) for ep in episodes: print(ep.get("title"), ep.get("content")) # after episodes = app.memory.search_episodes(query="policy quote", top_k=10) for ep in episodes: print(ep.metadata.get("title"), ep.content)
# build_context: str → ContextResponse.formatted_context # before prompt = app.memory.build_context(query="help me", user_id="u1") # after context = app.memory.build_context(query="help me", user_id="u1") prompt = context.formatted_context
Migração de referência (no repositório de exemplos do Agent Engine):
agents/insurance-agent/src/insurance_agent/main.py
As diferenças de capacidade por backend e as lacunas vinculadas ao aplicativo são documentadas na matriz de recursos do pacote de memória. Documentos em nível de métodopara a face Memory estão ativos em Agent-engine-sdk-memory.
Habilite a memória com features.memory: true em agent.yaml ou com a variável de ambiente ENABLE_MEMORY=true legado quando esse sinalizador de recurso for omitido. Os aplicativos existentes ainda podem passar enable_memory=... ou enable_tracing=... para App(...), mas esses sinalizadores de construtor estão obsoletos: mova a memória para agent.yaml e remova enable_tracing completamente porque o rastreamento está sempre ativado.
Habilidades
As habilitações são arquivos de marcação nomeados (SKILL.md) que o LLM pode carregar sob demanda por meio de abertura gradual. Use-os para codificar a experiência do domínio (por exemplo, regras de revisão de segurança, convenções de codificação) que sobrecarregariam o prompt do sistema se sempre incluídos.
layout do diretório
my_agent/ skills/ security-checklist/ SKILL.md style-guide/ SKILL.md
Passe o diretório principal skills/ para skills=[...]. No tempo de execução, os agentes listam esse diretório por meio do backend configurado e descobrem cada diretório filho imediato que contém SKILL.md como uma habilidade. A descoberta é um nível de profundidade, não recursiva.
frontmatter do SKILL.md
--- name: security-checklist description: Security review rules for Python code, focusing on injection and auth --- # Security Checklist ## REVIEW-RULE-ID-SEC-1: SQL injection Never concatenate user input into SQL... ## REVIEW-RULE-ID-SEC-2: Command / path injection Calls to `subprocess.run`, `os.system`, `shell=True`, and `open()` must not interpolate untrusted input...
agentes secretos validam o frontmatter da habilidade no tempo de execução. Ele ignora frontmatter ilegível ou analisável e habilidades faltando name ou description; As violações de nomenclatura de habilidades do agente ou de nome de diretório produzem avisos, mas ainda podem carregar. O SDK encaminha caminhos declarados sem inspecioná-los ou filtrá-los.
Conectando habilidades ao seu agente
Observação
Pré-requisitos: agent.yaml deve incluir features.deep_agent: true ou App.deep_agent() aumentará RuntimeError no momento da construção:
features: deep_agent: true
from langchain_openai import ChatOpenAI from agent_engine_sdk_langgraph import App app = App(app_name="My Reviewer") def build_agent(): return app.deep_agent( llm=ChatOpenAI(model="gpt-5.4"), system_prompt="You are a code reviewer.", skills=["skills"], ) app.run()
Cada entrada skills=[...] é um diretório de origem principal, não um diretório de habilidade de folha ou um arquivo SKILL.md. Os caminhos são relativos ao diretório que contém agent.yaml, então skills=["skills"] funciona para imagens de agente único (/app/skills) e imagens de monorepo (/app/<agent-subdirectory>/skills). Se suas habilidades estiverem em outro lugar dentro da árvore de origem do agente , defina AGENTIC_SKILLS_DIR para esse diretório relativo e torne skills=[...] relativo a ele. No tempo de execução, o deepagents lê o frontmatter de cada habilidade descoberta e passa seus metadados (nome, descrição e caminho resolvido) para o LLM como um bloco de sistema de habilidades no prompt do sistema.
Atualização contínua
Na curva 1, o LLM vê apenas os metadados das habilidades, não os corpos. Quando um usuário pergunta sobre segurança, o LLM decide fazer read_file("<agent-dir>/skills/security-checklist/SKILL.md"), e o corpo inteiro chega como ToolMessage no contexto da vez 2.
Isso mantém o prompt de base simples (os metadados são de aproximadamente 50 tokens por habilidade), permitindo que experiência profunda seja carregada sob demanda.
Arquivos de habilidade agrupados e sandbox
O sistema de arquivos gravável do ToolPod e os manipuladores de shell ainda usam WORKSPACE_DIR, que é padronizado como /tmp/agent-workspace. Mantenha isso como espaço zero.
Em vez disso, as habilidades agrupadas são tratadas como recursos somente leitura. O ToolPod deriva a raiz de habilitações padrão de AGENTIC_AGENT_CONFIG_PATH ou AGENTIC_AGENT_WORKDIR: se a configuração de tempo de execução for /app/agent.yaml, a raiz de habilitações será /app/skills; se a configuração de tempo de execução for /app/agents/reviewer/agent.yaml, a raiz das habilitações será /app/agents/reviewer/skills. AGENTIC_SKILLS_DIR substitui essa raiz e deve ser relativo à raiz de origem do agente . As ferramentas do sistema de arquivos somente leitura podem carregar arquivos nessa raiz sem definir WORKSPACE_DIR no diretório de habilidades. As operações de gravação, edição e shell ainda permanecem no espaço de trabalho gravável. A raiz de habilidades é resolvida na inicialização do Pod da Ferramenta, não no momento da importação do SDK, portanto, uma importação normal do SDK estática funciona — nenhuma solução alternativa na ordem de importação é necessária.
Não herança do subagente
As habilidades são visíveis apenas para o agente que as declara. Se o seu agente gerar subagentes (por meio da ferramenta
task), esses subagentes não herdarão as habilidades dos pais. Passeskills=[...]em cada especificação de subagente que precisa de arquivos de habilidade.
Nomes de ferramentas reservados
O tempo de execução do agente secreto reserva 9 nomes de ferramentas para integrados.Não registre @app.tool() com nenhum desses nomes — ele sombreia silenciosamente o comportamento integrado e quebra as habilidades/sandbox:
read_file,write_file,edit_file,ls,glob,grep(sistema de arquivos)execute(shell)write_todos(planejamento)task(subagent dispatch)
Escolher um nome que corresponda sombreará silenciosamente o integrado — não há erro de tempo de importação.
Orientação de tamanho
Meta < 200 linhas por corpo SKILL.md. Competências maiores:
Consome mais contexto quando carregado (cada
read_fileé um despejo de corpo inteiro)Corre o risco de atingir o limite de contexto de mensagem única do LLM em voltas complexas
Sugerir que a habilidade deve ser divisão em vários arquivos focados
Dica: redefina threads após editar SKILL.md
O tempo de execução armazena em cache skills_metadata no estado do agente durante a vida útil de um thread. Se você editar um arquivo SKILL.md, os threads existentes continuarão usando os metadados obsoletos até a redefinição. Em desenvolvimento: exclua o tópico ou inicie uma nova sessão. Em produção: as mudanças de habilidades devem ser emparelhadas com um novo modelo/lançamento de versão de prompt.
exemplo mínimo completo
Consulte o repositório de exemplos do Code Analyzer Agent no Agent Engine para ver uma implementação de referência:
Repositório de exemplos do Agent Engine
agents/code-reviewer-agent/src/code_reviewer_agent/main.py— fiaçãoRepositório de exemplos do Agent Engine
agents/code-reviewer-agent/skills/*/SKILL.md— exemplo de habilidades
Streaming
LangGraphBaseAgent.stream() produz StreamEvent objetos. Itere com async for para receber atualizações em nível de token, marcadores de ciclo de vida de subagentes e o resultado final.
event | Quando disparado | data Campos |
|---|---|---|
| Cada chunk de token LLM do agente raiz ou de qualquer subagente ativo. |
|
| Tem início uma execução de subagente. Emitido de um dos dois caminhos: (1) primário - a ferramenta_call |
|
| Uma execução de subagente é concluída. Caminho primário: o gráfico principal observa um |
|
| Conclusão final do agente raiz . |
|
| Interrupção HITL — o gráfico está pausado aguardando revisão humana. |
|
Notas para consumidores:
subagent_startesubagent_endestão sempre emparelhados, inclusive em encerramento anormal. O braço de limpeza emstream()distingueGeneratorExit(desconexão do consumidor - cai o estado sem ceder, uma vez que nenhum consumidor permanece) dos erros do lado do provedor (produzsubagent_enddefensivo e depois aumenta novamente).Para despachos paralelos do mesmo tipo de subagente, cada invocação tem seu próprio
tool_call_id. Prefiratool_call_idpara tokens de roteamento e volte parasourcesomente quandotool_call_id == "".subagent_end.summaryé o texto de resposta final do subagente — a mesma string que o agente pai verá como o valor de retorno da ferramentatask.
Interrupções nativas duráveis
Fluxos de trabalho duráveis reproduzem a chamada interrupt() nativa do LangGraph e traduzem seu ID nativo recém-gerado para a posição de atividade OE registrada anteriormente. Consulte Interrupção e retomada do Durable LangGraph para o fluxo completo de suspensão, repetição e Command(resume=...) e seus sites de chamada de código.
Referência da API
Consulte docs/api.md para a superfície App/LingGraph gerada automaticamente. Para a aparência do Memory (métodos, tipos de retorno, regras de identidade), consulte Agent-engine-sdk-memory e sua matriz de capacidade.
Configuração
Variável de ambiente | Default | Descrição |
|---|---|---|
|
| Nome de base para o armazenamento MongoDB por projeto usado para checkpoints LangGraph (somente modo AER). O escopo/descoberta do projeto ainda se aplica, a menos que seja substituído abaixo. |
| (desconfigurar) | Nome exato do banco de dados MongoDBSaver quando definido. Ignora o escopo e a descoberta do projeto . Opte por DBs de checkpoint compartilhados de tempo de execução duplo (definidos no pod AER do agente env / SecretRefs). |
|
| Segundos para a seleção do servidor de checkpointer do MongoDB antes que o checkpoint IO falhe. |
|
| Segundos para o estabelecimento da conexão do checkpointer do MongoDB . |
|
| Segundos para leituras/gravações do soquete do checkpointer do MongoDB . |
Por padrão, o checkpoint do LangGraph thread_id é session_id:workspace_id. Os agentes podem substituir isso por @app.resolve_thread_id (valor de retorno usado textualmente em novos e currículos). As chaves personalizadas são invisíveis para as pesquisas de histórico /query/sessions* do Atlas Agent Engine, que ainda usam apenas as chaves padrão derivadas da sessão/espaço de trabalho. Os agentes que ignoram o escopo do espaço de trabalho também possuem isolamento de colisão dentro do banco de dados de checkpoint .
A viagem no tempo do LangGraph corrigiria a origem thread_id. Em vez disso, o Atlas Agent Engine cria uma nova sessão. As sessões de checkpoint nativo copiam um checkpoint concluído para uma nova thread; ramificação de sessões de fluxo de trabalho durável do estado validado pelo OE reconstruído em arranhões protegidos. Consulte Session fork vs LangGraph time-travel.
Documentos de aprendizado da plataforma (o que é fluxo de trabalho durável, primitivos, habilitações, restrições): fluxo de trabalho durável. O modelo de repetição compartilhado de Ferramenta e LLM é descrito em Identidade de atividade durável. Consulte Subgrafos compilados duráveis e Delegação de agente profundo durável para obter diagramas de sequência completos, exemplos e mapas de site de chamada de código. Somente os efeitos roteados pelos wrappers seguros de LLM e Ferramentas do Atlas Agent Engine participam de registros/replays duráveis. Para uma repetição durável da ferramenta, o ToolCall deve vir do wrapper LLM seguro e ser executado por meio de uma ferramenta retornada por app.get_tools().
Fluxos de trabalho duráveis não expõem a função dinâmica `Send< https://docs.langchain.com/oss/python/langgraph/graph-api#send>'__ fa-out. O checkpoint normal da plataforma rejeita escritas Send criadas pelo aplicativo. Os gráficos criados por app.deep_agent() são uma exceção opaca porque o LangChain usa Send internamente para rotear ToolsCalls; essa compatibilidade privada não torna a Send uma API de aplicação compatível. Em vez disso, use bordas de gráfico fixas, subgráficos compilados ou delegação de tarefas do Open Agent. Os fluxos de trabalho dos pontos de verificação nativos não são afetados.
As leituras são somente com escopo. O histórico de sessões expande cada Atlas Agent Engine session_id apenas para sua chave composta com escopo de espaço de trabalho; a chave simples sem escopo nunca é consultada depois que o escopo do espaço de trabalho é conhecido, porque as chaves vazias são legíveis e graváveis por todos os espaços de trabalho no armazenamento compartilhado. Portanto, os checkpoints legados escritos antes da existência do escopo não são mais atendidos pelos endpoints do histórico; não adicione novamente o fallback. Um escopo vazio é legítimo somente em tempos de execução explicitamente sem escopo (desenvolvimento / testes locais, não APP_ID). AERs gerenciados carregam REQUIRE_PROJECT_SCOPED_DB; se APP_ID estiver ausente lá, as leituras e as gravações falharão fechadas em vez de confiar no espaço de trabalho do fio ou usar chaves simples. Os usuários de produção de chaves personalizadas ainda devem tratar a exclusividade da chave de checkpoint dentro de um banco de dados compartilhado como de propriedade do agente.
Desenvolvimento
Requisitos
Python >= 3.11
Configuração do desenvolvedor
uv sync --extra dev
Teste
Para as mesmas verificações executadas de CI (lint + formato + pyright + testes), use o executor unificado: ./scripts/test.sh agent-engine-sdk-langgraph da raiz do repositório.
uv run pytest
Verificação de tipo
uv run pyright
Regenerar documentos API
make docs
Linting & Formatação
# Check for lint errors uv run ruff check src # Auto-fix lint errors uv run ruff check --fix src # Format code uv run ruff format src