Migrating Langchain To Pydantic AI
PydanticOfficialPublished by Pydantic
- Skill
- Workflow
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured methodology for porting existing AI applications from the LangChain ecosystem to Pydantic AI. It emphasizes preserving application behavior over matching framework structures, advocating for a slice-based migration approach. The guide covers mapping core agent loops, handling complex state and persistence, and translating Deep Agents harness features into Pydantic AI primitives. It includes specific guidance on managing semantic gaps, verifying observability, and ensuring production readiness through characterization tests.
What it does
- Provides a step-by-step procedure for identifying and migrating functional slices of an application.
- Maps LangChain/LangGraph concepts to Pydantic AI primitives.
- Offers strategies for translating Deep Agents harness features like filesystem tools, subagents, and memory.
- Defines best practices for handling dependencies, typed invariants, and observability.
- Includes guidance on managing semantic differences and verifying parity through testing.
- Outlines the process for production cutover and verification.
When to use it
- When you need to migrate an existing LangChain or LangGraph application to Pydantic AI.
- When your application uses Deep Agents and requires a transition to Pydantic AI Harness.
- When you need to ensure behavioral parity during a framework migration.
- When you need to resolve semantic differences between LangChain and Pydantic AI implementations.
Advantages
- Focuses on behavioral preservation rather than superficial code matching.
- Provides a clear, risk-aware path for complex agentic systems.
- Includes specific mapping references for core loops and harness features.
- Encourages the use of typed dependencies for better reliability.
- Promotes a test-driven approach to ensure migration accuracy.
Usage examples
- “How do I migrate a simple LangChain agent to Pydantic AI?”
- The agent will guide you to identify the agent's tools and system prompt, then show you how to define a Pydantic AI Agent with typed dependencies and instructions, replacing the LangChain constructor.
- “How should I handle Deep Agents subagents in Pydantic AI?”
- The agent will explain how to map the subagent's filesystem, skills, and memory middleware to Pydantic AI Harness capabilities or custom application services.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/pydantic/migrating-langchain-to-pydantic-ai/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip migrating-langchain-to-pydantic-ai.zip -d .agents/skills
Documentation by Pydantic
Migrate LangChain, LangGraph, and Deep Agents to Pydantic AI
Preserve behavior, not framework shape. Migrate the smallest behaviorally complete slice and leave application infrastructure outside that slice unchanged. LangChain, LangGraph, and Deep Agents are one source ecosystem; Pydantic AI, pydantic_graph, and Pydantic AI Harness are the matching target ecosystem, and this skill maps across all of it.
Work from the running application
Read repository instructions, dependency files, tests, and the actual runtime entrypoints. Identify the installed LangChain, LangGraph, Deep Agents, Pydantic AI, and Harness versions.
Trace one representative request through prompts, retrieval, model and tool calls, state, persistence, interrupts, emitted events, tracing/metrics callbacks, and the public result. Inspect every caller and sibling endpoint that consumes the migrated component; a narrow implementation slice can still have several public contracts. Include keyword parameter names and the sync, async, callback, and streaming forms callers actually use. Record only contracts those paths actually use.
Run the cheapest useful baseline. When the migration surface is broad or unclear, search dependency files and source for
langchain,langgraph,langsmith, anddeepagents, then confirm findings against imports, factories, and call sites. Resolve wherecreate_deep_agentcomes from: the upstream package and a vendored copy that reproduces its contracts both count as Deep Agents.Classify the slice before choosing a target:
Chain or LCEL pipeline: keep deterministic retrieval and transformation in plain Python; use a Pydantic AI agent only where a model/tool loop adds value.
LangChain agent: normally use one reusable
pydantic_ai.Agentwith typed dependencies, tools, and outputs.Direct LangGraph workflow: use plain async Python for simple fixed control flow, or
pydantic_graphwhen explicit typed nodes and branching remain useful. Treat persistence as a separate design decision.Deep Agents harness:
create_deep_agentbundles file tools, shell execution, subagent delegation, summarization, skills, memory, permissions, prompt caching, and approval middleware on top of the LangChain agent loop, and a harness profile can add or hide more. Migrate the loop with the LangChain mappings, then map each bundled feature the slice actually uses to a Harness capability, a core primitive, or an application service with Deep Agents Mapping. Inventory implicit defaults the application code never mentions.Product runtime: retain queues, configured database backends, sandboxes, auth, schedulers, webhooks, tracing, and transport adapters unless the user placed them in scope. Extend an existing application seam before creating a parallel persistence or provider subsystem.
Add or preserve deterministic characterization tests, then migrate one vertical slice behind the existing public boundary.
Run the original tests and focused parity tests. Classify each observed contract by its evidence; never describe the migration as one-to-one merely because the happy path or trace shape looks similar.
Read Concept Mapping for the detected source features. Read Deep Agents Mapping whenever deepagents is in the slice. Read Semantic Gaps only for state, middleware, retries, approval, concurrency, streaming, or other behavior where similar-looking APIs may differ. Use Workaround Recipes after a concrete gap is identified, not as a mandatory checklist. Read Logfire Verification when adding observability, comparing source and target runs, or debugging a semantic difference. Read Verification and Cutover before a production cutover.
Explain semantic differences
When an observed source contract has no direct equivalent, explain it to the user before making a consequential design choice. State the source behavior, how the proposed Pydantic AI design differs, the user-visible or operational impact, and the available choices. Recommend one option and name its residual risk. Keep this proportional: do not turn ordinary import or naming changes into semantic warnings.
Do not stop at "unsupported." When nothing maps directly, recommend an existing core or Harness composition, a narrow adapter or application service, a new capability built from public primitives, or a core change, in that order of preference. Ask before choosing only when the options materially change behavior, architecture, public API, or scope.
Match rigor to risk
For a stateless chain or ordinary agent port, focused characterization tests and a short residual-risk note are enough. Do not require a semantic-gap register or durability exercise for behavior the source does not have.
For middleware, structured output transport, retrieval, tool retries, or streaming, probe the affected contract against the installed versions.
For checkpointed graphs, interrupts, approvals, durable execution, concurrent fan-out, or external side effects, create a migration ledger. Separate dependencies, messages, workflow state, checkpoint state, and long-term memory. Fit those owners into the repository's existing backend-selection and service interfaces where possible. Test restart, replay, correlation, authorization, and idempotency only to the extent the source promises them.
A
deepagentsdependency alone changes nothing. When the active slice callscreate_deep_agentor depends on its planning, filesystem, sandbox, skills, memory, subagent, permission, or deployment contracts, those are in-scope features with Harness or application owners, not a reason to stop. Files, sandboxes, permissions, subagents, and background work carry the same ledger and restart obligations as checkpointed graphs.
Pydantic AI defaults
Put authenticated identity, service clients, and configuration in typed dependencies, never model-chosen tool arguments.
Strengthen observed unstable seams, not the whole application: parameterize the agent's dependency and output types, and validate terminal choices, persisted workflow records, and framework adapters. Preserve stable public wire shapes and do not invent types for paths outside the migrated slice.
Preserve public request, response, error, and event shapes with a small adapter while callers migrate.
Keep retrieval, storage, provider, and transport integrations in place when they are outside the requested slice. Transitional LangChain integrations are acceptable when named and bounded.
Use Pydantic models for terminal structured output when that preserves the contract; retain an existing parser when changing the wire contract would expand the migration.
Do not force an
Agentonto deterministic LCEL orpydantic_graphonto everyStateGraph.Inspect the installed Pydantic AI API before choosing model classes, provider transports, hooks, streaming methods, or durable integrations.
Add
pydantic-ai-harnessonly for observed harness behavior: planning, workspace files, shell or sandboxed execution, Agent Skills, memory notebooks, repository context, model-directed subagents, model-agnostic compaction, tool-output limits, guardrails, spend limits, or step persistence. Add capabilities one at a time, import each from its owning public submodule, treatpydantic_ai_harness.experimental.*as version-sensitive, and run an import-and-construction smoke test in the target environment. Harness composes onto the core agent loop; it is not a second runtime and does not replace application infrastructure.When adding Pydantic AI, prefer a currently supported stable release. Use the newest compatible release unless that would expand the migration through an unrelated major/runtime upgrade; explain and pin any exception. Resolve the whole project from a clean environment and run an import probe because an existing environment can hide incompatible transitive versions. Prefer
pydantic-ai-slimwith only the required provider and integration extras when the dependency surface is bounded, and use the full distribution when its broader integrations are actually needed. Do not pin an older release merely to match a remembered example.If the source already uses LangSmith, Langfuse, or another observability system, do not replace it silently. Explain that Logfire is the first-party Pydantic AI integration and normally provides the most direct agent, model, tool, retry, error, usage, and timing experience. Contrast that with the continuity of retaining the current system, including its dashboards, alerts, evaluations, retention, and export pipeline; recommend a choice and obtain agreement before switching. Offer Logfire at application startup when no tracing system exists or the user chooses it, make content capture an explicit privacy decision, and keep executable contract tests as the authority for parity.
Completion
The slice is complete when every observed contract is either preserved by an executable check, intentionally changed by an accepted decision, or explicitly not applicable. An untested contract is unverified, not equivalent; an unresolved requested contract is unfinished work, not completion evidence. Constrain the slice or ask the user to accept the deferral. Remove LangChain, LangGraph, or Deep Agents dependencies only after no retained path needs them.
Files
- ATTRIBUTION.mdAdded by AutoGineer885 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md9.9 KiB
- agents/openai.yaml394 B
- references/CONCEPT-MAPPING.md16.2 KiB
- references/DEEP-AGENTS-MAPPING.md24.5 KiB
- references/LOGFIRE-VERIFICATION.md10.2 KiB
- references/SEMANTIC-GAPS.md21.6 KiB
- references/VERIFICATION-AND-CUTOVER.md12.3 KiB
- references/WORKAROUND-RECIPES.md18.0 KiB
references/DEEP-AGENTS-MAPPING.md
Deep Agents Mapping
Use this reference when the slice calls create_deep_agent, or a vendored equivalent, or depends on Deep Agents middleware, backends, profiles, skills, memory, subagents, permissions, sandboxes, or hosts. Deep Agents is an opinionated harness over the LangChain agent loop and the LangGraph runtime; Pydantic AI Harness is the matching capability library over the Pydantic AI agent loop. Map behavior to behavior, then confirm every candidate against the locked source and target versions. Rows that concern the plain agent loop, tools, structured output, state, or streaming are in Concept Mapping; this file covers what the harness adds on top.
Contents
What the harness bundles
Construction, models, and middleware
Context and execution
Orchestration and recovery
Hosts and protocols
A tested Harness composition
Migration traps
What the harness bundles
Translating constructor arguments one by one misses the harness. Snapshot the resolved agent instead: the effective prompt, the model-visible tool list, the middleware order on the main agent and on every subagent, the state schema, and the runtime configuration. In current deepagents releases the defaults are:
Tools:
ls,read_file,write_file,edit_file,glob, andgrep;executeonly when the resolved backend supports shell execution;taskwhen inline subagents or the general-purpose child are enabled.write_todosexists only before 0.7 or with an explicitly configured todo middleware.Prompt: the caller's
system_prompt, then the harness profile'sbase_system_prompt, then itssystem_prompt_suffix, with skills, memory, and filesystem middleware injecting more text per request.Middleware order: skills, filesystem, subagents, summarization, patch-tool-calls, async subagents; then caller middleware; then profile
extra_middleware, tool exclusion, provider prompt caching, memory, and human-in-the-loop. Profiles can exclude entries by class or name.Profiles:
HarnessProfileshapes prompt layers, tool descriptions and exclusions, excluded middleware, and the general-purpose child;ProviderProfileshapes model construction. A Pydantic AI model profile configures provider behavior only; it never configures the Harness composition, so profile-driven differences must be reproduced explicitly.Subagent stacks: each declarative child gets its own filesystem, skills, memory, and exclusion middleware; a compiled child is whatever the caller built; an
AsyncSubAgentis a remote LangGraph deployment. A behavior seen only during delegated work may come from any of these.
Record which of these the application actually exercises. An unused default is not-applicable, not a migration task.
Construction, models, and middleware
| Deep Agents contract | Pydantic AI candidate | Required check |
|---|---|---|
create_deep_agent | Agent(...) with explicit instructions, tools, toolsets, capabilities, output type, and settings | Snapshot the effective prompt, tool schemas, profile behavior, result, errors, and limits. |
LangChain BaseChatModel | a Pydantic AI provider model or model string | Do not pass the LangChain model through. Translate transport, endpoint, authentication, provider settings, model profiles, retries, and limits. Construct and validate every configured model branch. |
| harness and provider profiles | explicit agent configuration plus Pydantic AI model settings and profiles | Trace provider/model lookup and merge order. Preserve prompt layers, tool descriptions and exclusions, middleware changes, general-purpose-child settings, and model-construction defaults. |
graph .invoke(), .ainvoke(), .stream(), .astream(), or event callbacks | run_sync, run, run_stream, run_stream_events, iter, and event_stream_handler | Use run_stream for final-output streaming; use run_stream_events or iter when the contract needs the complete tool/event lifecycle. Preserve sync, async, result, message, error, and event shapes at the application boundary. |
context_schema | deps_type and RunContext | Dependencies are runtime resources and identity, not checkpointed state. |
custom state_schema and reducers | capability-owned run state, an application repository, or pydantic_graph | Classify each field's lifecycle and merge semantics. |
| custom or replaced middleware | a core capability, Hooks, a wrapper toolset, or a focused Harness capability | Match hook timing, ordering, name-based replacement or exclusion, request mutation, retry, and failure behavior on main and child stacks. |
response_format | Pydantic output_type and an explicit output mode | Test invalid output, final-tool behavior, and streaming. |
| graph cache and provider prompt caching | application caching plus the selected Pydantic AI provider behavior | Separate graph-step caching from provider prompt caching; verify keys, scope, invalidation, cached content, usage, and replay behavior. |
| LangSmith, Langfuse, or other callbacks | retain the existing system, or use OpenTelemetry or Logfire after agreement | Compare correlation, dashboards, evaluations, retention, export, and privacy. Preserve conversation, run, child, tool-call, and external-job identities separately. |
Adapt LangChain @tool and StructuredTool objects to typed Pydantic functions or toolsets. Preserve their names, schemas, return values, and errors rather than passing framework objects through unchanged; the transitional wrappers in Concept Mapping apply here too.
For MCP, use pydantic_ai.capabilities.MCP when provider-native or client-side selection is needed; use pydantic_ai.mcp.MCPToolset for client-side MCP connections. Preserve transport, authentication, tool filtering, structured content, connection and session lifetime, elicitation, sampling, retries, and tracing at the integration boundary.
Context and execution
Import each capability from its owning public module, for example Skills from pydantic_ai_harness.skills and RepoContext from pydantic_ai_harness.repo_context; do not use compatibility modules left behind by a rename.
| Deep Agents feature | Harness candidate | Important difference |
|---|---|---|
| coding-agent defaults | Coder(workspace) | Compare its documented composition first. It is an opinionated local coding harness, not a guarantee of Deep Agents parity. Use individual capabilities when a component must change. |
| todo planning | Planning | Add it only when the source actually exposes write_todos or planning is an accepted addition. Harness has its own schema, tools, reminder injection, events, and stores. |
| local workspace files | FileSystem | It is a rooted local filesystem toolset, not Deep Agents' virtual BackendProtocol. Compare the installed tool schemas and limits: Deep Agents file tools use file_path, Harness uses path, and backend file-size limits need a separate guard. |
filesystem permissions | a wrapper toolset or capability, deferred approval, and backing-service authorization | Preserve operation classes, first-match rule order, unmatched-call behavior, allow/deny/interrupt results, route-relative paths, and child overrides. Deep Agents interrupt rules require a checkpointer; persist and restore the target approval continuation too. The rules cover built-in file tools, not arbitrary tools, direct backend access, or sandbox commands. |
| host or local shell execution | Shell | It runs host subprocesses. Its command filtering and path checks cannot reproduce a sandbox backend's OS isolation. |
| remote isolated execution (Modal, Daytona, Runloop, Vercel, LangSmith sandboxes) | ModalSandbox, or the existing sandbox client in typed deps behind narrow tools | Match lease, filesystem, network, credential, reconnect, timeout, and cleanup contracts. The sandbox service, not a tool filter, is the isolation boundary. |
| interpreter and programmatic tool calling | CodeMode, DynamicWorkflow, or an application interpreter | Deep Agents' QuickJS REPL persists state per thread by default, dispatches task(...), and calls tools.* only from an allowlist. Harness uses Monty and different tool schemas. Match state lifetime, structured results, resource limits, and authority; interpreter bridges can bypass ordinary tool-approval paths unless guarded explicitly. |
| multimodal input, file reads, or tool results | Pydantic AI user content and ToolReturn; pydantic_ai_harness.media stores and walkers for persistence offload | Keep model-facing content in Pydantic AI types. With StepPersistence, configure media_store on its FileStepStore, SqliteStepStore, or MongoStepStore; for another serializer, use externalize_media and restore_media directly. Preserve order, MIME support, provider filtering, references, serialization, and restoration. |
skills=[...] and SKILL.md catalogs | Skills | Pass the parent skill-library directory whose immediate children are <name>/SKILL.md packages. Harness scans it at construction and keeps that snapshot. Normalize flat catalogs into this shape; do not replace it with eager prompt concatenation. Harness loads instructions only: preserve bundled files, scripts, writable catalogs, and behavioral frontmatter with a focused service only when those contracts matter. |
AGENTS.md and repository instructions | RepoContext | Configure workspace_dir, home_dir, filenames, autoload_instructions, expose_inventory_tool, inventory_tool_name, asset_roots, nested_traversal, and nested_inject from observed discovery and injection behavior. Compose it with FileSystem when file traversal should inject nested context. It does not replace skill activation or writable memory. Never promote untrusted repository text to system priority accidentally. |
memory=[...] and writable long-term memory | Memory | Check namespace, store, injection role and bound, search, concurrency, retention, and deletion. Deep Agents memory=[...] injects backend-relative files: use explicit instructions for static content, RepoContext for repository-owned context, and Memory or an application store for model-written notes. If callers use file tools at paths such as /memory/..., preserve those names with an adapter or intentionally change callers and prompts. |
| retrieval or RAG | existing retrieval services exposed as typed tools | Retrieval is application data access, not Deep Agents memory or a filesystem backend. Preserve ingestion, chunking, filters, tenancy, ranking, metadata, citations, result bounds, latency, and failure shapes. |
SummarizationMiddleware | Harness compaction capabilities, often TieredCompaction; provider-native compaction from core where the provider supports it | Harness rewrites Pydantic AI message history. Match thresholds, summary prompt and role, tool-pair validity, receipts, usage, and recovery. |
| oversized tool-result offload and message eviction | ToolOutputLimits with matching bands and store, or the retained backend artifact path | Use ToolOutputLimits(store=...) only when its overflow-store contract matches; otherwise retain or adapt the backend artifact path. Human-message eviction needs separate handling. Verify thresholds, lossless versus lossy behavior, receipts, read-back, failure fallback, store lifetime, and serialization. |
| prompt-caching middleware | provider cache controls plus stable capability composition; WarnOnCacheBusts to detect prefix collapse | Compare exact cache markers and the effect of plans, memories, and compaction on the cached prefix. |
PatchToolCallsMiddleware | provider-valid history capture and an explicit continuation policy | Pydantic AI repairs dangling tool calls before a request; test malformed tails, orphan results, pending approvals, client-supplied history, and whether repair hides a real side effect. |
For pluggable or composite backends (StateBackend, StoreBackend, FilesystemBackend, CompositeBackend, sandbox backends), expose the existing storage or sandbox service through a focused toolset or capability. Preserve runtime-injected backend factories, route prefixes, path, tenancy, transaction, sandbox ownership, and lifecycle contracts instead of forcing them through local FileSystem. Preserve each route's storage lifetime and ownership: do not replace an ephemeral StateBackend route with persistent filesystem or store state.
Enforce authorization and isolation at the backing service. Treat prompt instructions, globs, path checks, and shell allowlists as defense in depth.
Orchestration and recovery
Import SubAgent and SubAgents from pydantic_ai_harness.subagents. Harness can load its Markdown agent format from configured folders, but it does not consume a Deep Agents YAML roster. Parse and validate retained application configuration into explicit Agent and SubAgent objects, or intentionally convert it: YAML system_prompt becomes Agent.instructions or the Markdown body, description remains the description, and tools become explicit toolsets or a tool_resolver. Set the child model explicitly or through AgentOverride; a model key in Harness Markdown is parsed but not applied.
| Deep Agents feature | Pydantic AI and Harness candidate | Important difference |
|---|---|---|
| synchronous named children and the general-purpose child | SubAgents, or a parent tool that runs a typed child Agent | Inspect the automatic general-purpose child and its disablement, isolated versus forked context, declarative versus compiled children, tools, skills, permissions, approvals, state, structured results, and streaming inheritance. Harness does not transfer mutable parent capability state implicitly; use explicit dependencies, shared_capabilities, or an application repository, then test child write visibility. |
model-written fan-out or chaining (QuickJS task(...)) | DynamicWorkflow | This is a redesign, not an API port: Deep Agents generates JavaScript for QuickJS, Harness generates Python for Monty and calls child agents from run_workflow. Verify structured results, interpreter and thread state, nesting, and tool boundaries. Neither is a durable background task service. |
AsyncSubAgent background work | an application queue/worker plus narrow start, list, check, update, and cancel tools | Preserve graph ID, transport and authentication, task/thread/run identity, pending state, stale reads, steering, cancellation, and result durability. Harness synchronous delegation and generated workflows are not background-task services. |
RubricMiddleware grading loop | an explicit evaluator/revision loop or focused capability | Preserve the invocation rubric, grader model and tools, revision feedback, iteration limit, terminal verdict, callbacks, and progress events. TrajectoryJudge provides cadence-based mid-run steering, so use it only when that different lifecycle is accepted. |
interrupt_on and approval | DeferredToolRequests, DeferredToolResults, ToolApproved, and ToolDenied | Include DeferredToolRequests in output_type. When returned, persist result.all_messages(), resolve the request with build_results(...), then call run(message_history=..., deferred_tool_results=...). Use HandleDeferredToolCalls only for an in-process handler whose lifecycle is sufficient. The LangGraph Command(resume=...) protocol is not reproduced; see Workaround Recipes for the durable record. |
| provider-valid run snapshots | StepPersistence | It records step events, continuable snapshots, lineage, and tool effects; it is not arbitrary LangGraph graph-state checkpointing. |
| durable model and tool execution | TemporalDurability, DBOSDurability, PrefectDurability, AWSLambdaDurability, or another matching integration | Select by the deployment contract and install its extra. Wire the integration's workflow or handler boundary, not only its capability; verify crash and redeploy recovery, replay, timers, signals, and side-effect idempotency in that runtime. |
| retries, fallbacks, and call limits | Pydantic AI tool/output retries, provider transport retries, FallbackModel, UsageLimits, Harness SpendLimits, and application or durable-workflow policy | Classify expected versus unexpected errors and retry scope. Match backoff, fallback order, tool-error visibility, counters, terminal propagation, and side-effect idempotency. |
| LangGraph and Deep Agents event streaming | Pydantic AI streaming APIs plus capability event handlers | Translate the application's selected modes and projections. Namespaced graphs and subagent handles with child identity, status, messages, tool calls, nested work, and output are not preserved automatically. |
Explicit designs for gaps:
Forked child context or compiled LangGraph children: pass selected context explicitly, rebuild the child with Pydantic AI primitives, or retain it behind a typed tool boundary during migration.
Background subagents: keep the queue and worker in the host. Give the agent narrow start, list, inspect, steer, and cancel tools with tenant checks, idempotency keys, bounded retries, and durable results.
Approvals: test approve, deny, changed arguments, stale decisions, authorization changes, crash before and after execution, replay, and side-effect idempotency.
Checkpoints: separate message continuation, capability state, plans, files, approvals, domain state, and side effects. Do not replace a LangGraph checkpointer keyed by
thread_idwithStepPersistencewithout designing thread identity,message_historycontinuation, and ownership of the remaining state.Streaming: verify lineage, ordering, backpressure, redaction, child and tool events, error termination, and final-output timing.
Hosts and protocols
Migrate the underlying agent separately, then preserve the external contract with an adapter.
| Source surface | Target direction | Required check |
|---|---|---|
| Deep Agents Code or another CLI host | Coder or narrower Harness capabilities behind the existing command boundary | Inventory config and environment precedence, hooks and plugins, skills and memory roots, MCP servers, sandbox selection, approval modes, sessions, interactive and headless output, exit status, cancellation, and updates. Do not treat CLI behavior as create_deep_agent behavior. |
| frontend or AG-UI client | Pydantic AI UI adapters plus an application event/state adapter | Preserve coordinator messages, subagent projections, todo and custom state, tool-call lifecycle, interrupts, thread identity, reconnect behavior, files, sandbox artifacts, and final-result timing. |
| Agent Client Protocol | the experimental Harness ACP adapter when its session contract matches, otherwise an application adapter | Verify protocol negotiation, stdio lifecycle, sessions, content blocks, tool presentation, filesystem and terminal ownership, approvals, cancellation, history, errors, and client capability fallbacks. |
| A2A endpoint or client | an application server/client adapter around the migrated agent | Preserve the protocol version, agent card, methods, task and context identity, history, streaming, file parts, authentication, cancellation, tracing, and conformance behavior. |
| managed deployment | the selected host and application services | Preserve API and stream schemas, thread/run/store semantics, queues, schedules, tenancy, authentication, secrets, regional and data-retention rules, observability, retries, rollout, and recovery. |
If the target lacks a protocol feature, retain the existing adapter or propose a focused adapter built on public Pydantic AI run, message, event, and deferred-tool primitives. Do not bury a wire-level behavior change inside the agent migration.
A tested Harness composition
Use this smoke test when a local coding-agent composition is plausible; Coder(workspace) is shorter when its documented defaults match the source. Run it in the exact target environment: it proves that imports and public constructor signatures resolve against the locked versions, not that behavior matches the source application.
# ruff: noqa: I001
import asyncio
from collections.abc import AsyncIterator
from pathlib import Path
from tempfile import TemporaryDirectory
from pydantic_ai import Agent
from pydantic_ai.messages import ModelMessage
from pydantic_ai.models.function import AgentInfo, FunctionModel
from pydantic_ai.models.test import TestModel
from pydantic_ai_harness.compaction import SlidingWindowCompaction
from pydantic_ai_harness.filesystem import FileSystem
from pydantic_ai_harness.planning import Planning
from pydantic_ai_harness.repo_context import RepoContext
from pydantic_ai_harness.skills import Skills
from pydantic_ai_harness.subagents import SubAgent, SubAgents
async def stream(_messages: list[ModelMessage], _info: AgentInfo) -> AsyncIterator[str]:
yield 'Workspace ready.'
worker = Agent(TestModel(call_tools=[]), name='researcher', description='Research a bounded question.')
with TemporaryDirectory() as workspace:
root = Path(workspace)
skill = root / 'skills' / 'inspect-workspace'
skill.mkdir(parents=True)
(skill / 'SKILL.md').write_text(
'---\nname: inspect-workspace\ndescription: Inspect a workspace.\n---\nUse read-only tools.',
encoding='utf-8',
)
migrated = Agent(
FunctionModel(stream_function=stream),
output_type=str,
instructions='Work only inside the configured workspace.',
capabilities=[
Planning(),
FileSystem(root, read_only=True),
RepoContext(workspace_dir=root),
Skills(root / 'skills'),
SubAgents(agents=[SubAgent(worker, max_calls=1)], agent_folders=None),
SlidingWindowCompaction(max_messages=20, keep_messages=10),
],
)
result = asyncio.run(migrated.run('Describe the available workspace tools.'))
assert isinstance(result.output, str)
assert result.all_messages()Use TestModel(call_tools=[]) for construction-only checks and a FunctionModel with scripted tool calls when a test claims tool behavior. Event-aware capabilities such as RepoContext can make Agent.run() use the streamed model path, so provide stream_function and execute the complete composition once rather than inferring the path from the model stub.
Migration traps
Treating a
deepagentsimport as out of scope, or as a reason to hand the migration to another skill, instead of mapping the bundled features it actually uses.Translating
create_deep_agent(...)arguments without snapshotting the profile-resolved prompt, tools, and middleware.Passing a LangChain
BaseChatModelor LangChain tools through unchanged.Replacing a sandbox backend with local
ShellorFileSystem, or treating path checks and allowlists as the isolation boundary.Turning
/memory/...file paths into HarnessMemorywithout preserving the tool names, paths, and injection role callers depend on.Replacing a LangGraph checkpointer with
StepPersistenceormessage_historyalone.Assuming
write_todos, the general-purpose child, or summarization exists on the source without checking the installed version and profile.Reproducing
AsyncSubAgentwith synchronousSubAgentsorDynamicWorkflow.
Primary sources: Deep Agents architecture, create_deep_agent source, profiles, backends, permissions, sandboxes, subagents, async subagents, human-in-the-loop, Deep Agents Code, Pydantic AI Harness, Pydantic AI capabilities, deferred tools, and durable execution.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Pydantic
- Publisher
- Pydantic (Official)
- Source
- pydantic/skills · skills/migrating-langchain-to-pydantic-ai · commit 98f591c
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Also distributed in
- pydantic/skills
AutoGineer is not affiliated with or endorsed by Pydantic.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download migrating-langchain-to-pydantic-ai.zip