Generated banner for Migrating Langchain To Pydantic AI
Generated logo for Migrating Langchain To Pydantic AI

Migrating Langchain To Pydantic AI

PydanticOfficialPublished by Pydantic

  • Skill
  • Workflow
  • Software development
  • MIT
  • No issues found

From the author

Migrate Python LangChain, LangGraph, or Deep Agents applications to Pydantic AI and, when the source uses harness features, Pydantic AI Harness. Use for LangChain agents, chains, LCEL, direct LangGraph graphs, persistence, interrupts, streaming, and `create_deep_agent` projects with planning, filesystem or sandbox backends, skills, memory, subagents, permissions, approvals, or Deep Agents Code hosts.
— the description by Pydantic

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

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/pydantic/migrating-langchain-to-pydantic-ai/download
  2. Unzip 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

  1. Read repository instructions, dependency files, tests, and the actual runtime entrypoints. Identify the installed LangChain, LangGraph, Deep Agents, Pydantic AI, and Harness versions.

  2. 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.

  3. Run the cheapest useful baseline. When the migration surface is broad or unclear, search dependency files and source for langchain, langgraph, langsmith, and deepagents, then confirm findings against imports, factories, and call sites. Resolve where create_deep_agent comes from: the upstream package and a vendored copy that reproduces its contracts both count as Deep Agents.

  4. 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.Agent with typed dependencies, tools, and outputs.

    • Direct LangGraph workflow: use plain async Python for simple fixed control flow, or pydantic_graph when explicit typed nodes and branching remain useful. Treat persistence as a separate design decision.

    • Deep Agents harness: create_deep_agent bundles 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.

  5. Add or preserve deterministic characterization tests, then migrate one vertical slice behind the existing public boundary.

  6. 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 deepagents dependency alone changes nothing. When the active slice calls create_deep_agent or 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 Agent onto deterministic LCEL or pydantic_graph onto every StateGraph.

  • Inspect the installed Pydantic AI API before choosing model classes, provider transports, hooks, streaming methods, or durable integrations.

  • Add pydantic-ai-harness only 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, treat pydantic_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-slim with 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

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, and grep; execute only when the resolved backend supports shell execution; task when inline subagents or the general-purpose child are enabled. write_todos exists only before 0.7 or with an explicitly configured todo middleware.

  • Prompt: the caller's system_prompt, then the harness profile's base_system_prompt, then its system_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: HarnessProfile shapes prompt layers, tool descriptions and exclusions, excluded middleware, and the general-purpose child; ProviderProfile shapes 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 AsyncSubAgent is 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 contractPydantic AI candidateRequired check
create_deep_agentAgent(...) with explicit instructions, tools, toolsets, capabilities, output type, and settingsSnapshot the effective prompt, tool schemas, profile behavior, result, errors, and limits.
LangChain BaseChatModela Pydantic AI provider model or model stringDo 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 profilesexplicit agent configuration plus Pydantic AI model settings and profilesTrace 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 callbacksrun_sync, run, run_stream, run_stream_events, iter, and event_stream_handlerUse 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_schemadeps_type and RunContextDependencies are runtime resources and identity, not checkpointed state.
custom state_schema and reducerscapability-owned run state, an application repository, or pydantic_graphClassify each field's lifecycle and merge semantics.
custom or replaced middlewarea core capability, Hooks, a wrapper toolset, or a focused Harness capabilityMatch hook timing, ordering, name-based replacement or exclusion, request mutation, retry, and failure behavior on main and child stacks.
response_formatPydantic output_type and an explicit output modeTest invalid output, final-tool behavior, and streaming.
graph cache and provider prompt cachingapplication caching plus the selected Pydantic AI provider behaviorSeparate graph-step caching from provider prompt caching; verify keys, scope, invalidation, cached content, usage, and replay behavior.
LangSmith, Langfuse, or other callbacksretain the existing system, or use OpenTelemetry or Logfire after agreementCompare 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 featureHarness candidateImportant difference
coding-agent defaultsCoder(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 planningPlanningAdd 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 filesFileSystemIt 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 permissionsa wrapper toolset or capability, deferred approval, and backing-service authorizationPreserve 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 executionShellIt 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 toolsMatch lease, filesystem, network, credential, reconnect, timeout, and cleanup contracts. The sandbox service, not a tool filter, is the isolation boundary.
interpreter and programmatic tool callingCodeMode, DynamicWorkflow, or an application interpreterDeep 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 resultsPydantic AI user content and ToolReturn; pydantic_ai_harness.media stores and walkers for persistence offloadKeep 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 catalogsSkillsPass 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 instructionsRepoContextConfigure 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 memoryMemoryCheck 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 RAGexisting retrieval services exposed as typed toolsRetrieval 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.
SummarizationMiddlewareHarness compaction capabilities, often TieredCompaction; provider-native compaction from core where the provider supports itHarness rewrites Pydantic AI message history. Match thresholds, summary prompt and role, tool-pair validity, receipts, usage, and recovery.
oversized tool-result offload and message evictionToolOutputLimits with matching bands and store, or the retained backend artifact pathUse 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 middlewareprovider cache controls plus stable capability composition; WarnOnCacheBusts to detect prefix collapseCompare exact cache markers and the effect of plans, memories, and compaction on the cached prefix.
PatchToolCallsMiddlewareprovider-valid history capture and an explicit continuation policyPydantic 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 featurePydantic AI and Harness candidateImportant difference
synchronous named children and the general-purpose childSubAgents, or a parent tool that runs a typed child AgentInspect 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(...))DynamicWorkflowThis 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 workan application queue/worker plus narrow start, list, check, update, and cancel toolsPreserve 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 loopan explicit evaluator/revision loop or focused capabilityPreserve 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 approvalDeferredToolRequests, DeferredToolResults, ToolApproved, and ToolDeniedInclude 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 snapshotsStepPersistenceIt records step events, continuable snapshots, lineage, and tool effects; it is not arbitrary LangGraph graph-state checkpointing.
durable model and tool executionTemporalDurability, DBOSDurability, PrefectDurability, AWSLambdaDurability, or another matching integrationSelect 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 limitsPydantic AI tool/output retries, provider transport retries, FallbackModel, UsageLimits, Harness SpendLimits, and application or durable-workflow policyClassify 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 streamingPydantic AI streaming APIs plus capability event handlersTranslate 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_id with StepPersistence without designing thread identity, message_history continuation, 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 surfaceTarget directionRequired check
Deep Agents Code or another CLI hostCoder or narrower Harness capabilities behind the existing command boundaryInventory 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 clientPydantic AI UI adapters plus an application event/state adapterPreserve 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 Protocolthe experimental Harness ACP adapter when its session contract matches, otherwise an application adapterVerify protocol negotiation, stdio lifecycle, sessions, content blocks, tool presentation, filesystem and terminal ownership, approvals, cancellation, history, errors, and client capability fallbacks.
A2A endpoint or clientan application server/client adapter around the migrated agentPreserve the protocol version, agent card, methods, task and context identity, history, streaming, file parts, authentication, cancellation, tracing, and conformance behavior.
managed deploymentthe selected host and application servicesPreserve 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 deepagents import 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 BaseChatModel or LangChain tools through unchanged.

  • Replacing a sandbox backend with local Shell or FileSystem, or treating path checks and allowlists as the isolation boundary.

  • Turning /memory/... file paths into Harness Memory without preserving the tool names, paths, and injection role callers depend on.

  • Replacing a LangGraph checkpointer with StepPersistence or message_history alone.

  • Assuming write_todos, the general-purpose child, or summarization exists on the source without checking the installed version and profile.

  • Reproducing AsyncSubAgent with synchronous SubAgents or DynamicWorkflow.

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 or Pydantic.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download migrating-langchain-to-pydantic-ai.zip