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://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/SEMANTIC-GAPS.md
Semantic Gaps and Parity Spikes
Use this reference when the source path has stateful, operational, or version-sensitive behavior whose target semantics are uncertain. A migration is safe only when each observed source guarantee is preserved, intentionally changed, or assigned to an explicit external owner.
Contents
Build a semantic-gap register
Prompts and message history
Tools, context, and schemas
Structured output and run termination
State, checkpoints, and approval
Middleware, retries, and limits
Streaming and event contracts
Concurrency and cancellation
Spike protocol
Primary references
Build a semantic-gap register
For a checkpointed, side-effectful, approval-gated, or otherwise high-risk slice, write this before target code. A simple stateless port can record the few applicable residuals alongside its tests instead:
| Source guarantee | Observed target behavior | Pydantic workaround | Outcome | Required probe | Residual / owner |
|---|---|---|---|---|---|
| checkpoint resumes after approval | deferred results start another agent run | deferred requests plus an authenticated durable pending-action record | unverified | crash before/after result persistence | selected workflow store / application workflow |
Classify each observed contract with the evidence statuses in Verification and Cutover: verified-equivalent, verified-adapter, intentional-change, external-owner, not-applicable, unverified, or blocked. A promising native API remains unverified until its parity probe passes. A source behavior may be non-equivalent internally while a tested adapter earns verified-adapter at the public boundary.
Deep Agents adds harness-level rows: profiles, backends and permissions, skills and memory injection, main and child middleware stacks, async subagents, rubric loops, interpreters, and hosts. Their candidate owners are in Deep Agents Mapping; classify them with the same statuses and probes.
Never use "native" to mean "the names look similar." Do not leave redesign as the proposed solution: follow the affected row into Validated Workaround Recipes, implement the smallest viable construction, and classify the resulting contract. Record installed versions and link each verified claim to an executable test; use traces, source lines, and official documentation as supporting evidence.
Prompts and message history
Current instructions versus historical prompts
Current LangChain create_agent keeps its request system message outside graph state and prepends it at the model boundary; dynamic prompt middleware replaces that request field rather than checkpointing a SystemMessage. Custom or legacy graphs may instead store explicit system messages, so inspect the source and capture the actual model request. Pydantic AI distinguishes instructions from system_prompt:
Current Pydantic AI
instructionsare sent for the current agent. Instructions stored on historicalModelRequestobjects are not model-visible instructions on the next run.Dynamic
@agent.instructionsfunctions are reevaluated for every run, including a run withmessage_history.Pydantic AI
system_promptis the historical-prompt mechanism. With non-empty history, a new system prompt is not generated unless the chosen reinjection behavior does so.
Do not mechanically replace every LangChain prompt with instructions or use Pydantic AI system_prompt merely because the source used the phrase "system prompt." Choose from observed model-boundary behavior:
| Required behavior | Pydantic AI choice |
|---|---|
| only the current agent's policy applies | instructions |
| historical prompts from earlier runs/agents remain authoritative | system_prompt plus tested history round-trip |
| UI/database history may omit the system prompt | sanitize history, then consider ReinjectSystemPrompt |
| per-request locale, tenant policy, or feature state | dynamic instructions from typed dependencies |
Probe the actual model boundary with FunctionModel and AgentInfo.instructions; inspecting serialized history alone is misleading because old request objects can still contain their original instructions field.
Multiple dynamic prompts also compose differently. LangChain dynamic_prompt middleware replaces the request's system message, and wrap middleware nests, so a later replacement can overwrite an earlier one. Pydantic AI composes registered instructions and orders stable static instructions before dynamic instructions. If the source has more than one prompt-mutating middleware, capture the exact final prompt and evaluation count; do not convert each entry to @agent.instructions and assume the concatenation is equivalent. When replacement is intentional, ordered Hooks.on.before_model_request processors can replace the latest request instructions; scrub those request-only instructions before persisting history if the source does not checkpoint them. Spike two dependency values and a continuation before adopting this adapter.
Message conversion is a protocol migration
LangChain messages and Pydantic AI messages differ in tool-call IDs, tool-return pairing, reasoning/provider metadata, multimodal parts, timestamps, and serialization. Do not cast or rename them in place.
Define and test a converter only when history must be retained. Include:
normal user/assistant turns;
multiple parallel tool calls and out-of-order returns;
interrupted or partially answered tool calls;
provider reasoning/signature metadata that must round-trip;
malformed or untrusted browser history;
branch/fork conversation identity.
Pydantic AI can repair model history before a request, including dangling tool calls and orphaned tool results. LangGraph's add_messages instead merges messages by ID. Feed malformed and partially completed histories through both implementations and compare the actual fake-model input, not only stored JSON.
Prefer an application-owned conversation DTO at public boundaries. Keep provider/framework messages inside adapters.
Tools, context, and schemas
ToolRuntime.context and RunContext.deps both inject runtime values, but parity depends on what the model can choose. Keep authenticated identity, credentials, clients, idempotency services, and policy evaluators out of the tool schema.
For every tool, diff the model-visible definitions from both implementations:
name and description;
parameter names, required fields, defaults, enums, nullability, and additional properties;
injected parameters excluded from JSON schema;
return content visible to the model versus application metadata;
validation error text and whether it is retried;
timeout, cancellation, idempotency, and side effects.
Pydantic AI's LangChain wrappers are transitional: LangChain retains argument validation and framework dependencies. A wrapped tool is not proof of native parity.
Audit source-only control flags before wrapping. For example, LangChain return_direct=True can end its agent immediately after the tool, while tool_from_langchain delegates the call without preserving that stop policy. If the model selects the call as a terminal action, make the callable a named output function with ToolOutput; a parity spike must prove the terminal value, one execution, and model-call count. This changes the callable from an ordinary optional tool into an output choice, so retain multiple output choices when the source has other terminal routes.
Sync Pydantic AI tools may run in worker threads while async tools run on the event loop. Test context propagation, cancellation, thread safety, and resource lifetimes when source tools relied on thread-local callbacks or event-loop affinity.
Structured output and run termination
The same schema type does not imply the same wire strategy:
LangChain may automatically choose
ProviderStrategywhen the selected model supports provider-native structured output, otherwiseToolStrategy.Pydantic AI resolves a plain structured
output_typethrough the selected model profile's default, which may be tool, native, or prompted output. SelectNativeOutput,ToolOutput,PromptedOutput, orTextOutputexplicitly when wire behavior matters.LangChain returns structured output in agent state (commonly
structured_response); Pydantic AI returnsresult.output. Preserve the application's public result DTO instead of exposing either shape.Pydantic AI unions that include
strpermit plain text to end the run. Exclude it when structured output is mandatory.
Characterize invalid schema retries, multiple output candidates, provider fallback, and a response that emits terminal output alongside function tools.
run() and run_stream() are not interchangeable
Pydantic AI run() completes the agent graph. run_stream() commits the first matching streamed output immediately. When a response co-emits structured output and a function tool, this can change the final result even if the agent uses the same end_strategy.
A verified probe should make the co-emitted function tool raise ModelRetry:
under
run()with the default graceful strategy, the first output is rejected and the corrected later output wins;under
run_stream(), the first matching output is already committed, so retry-after-tool-failure cannot replace it.
Use run(event_stream_handler=...), run_stream_events(), or iter() when the application needs complete agent execution plus events. Test the chosen method; do not infer parity from run() tests.
State, checkpoints, and approval
Split source state into four contracts:
run dependencies: typed services and immutable request context;
conversation: model messages;
workflow state: counters, plans, joins, pending actions, and domain progress;
long-term memory: cross-thread facts and retrieval indexes.
A LangGraph checkpointer stores graph state at super-step boundaries and may retain task-level pending writes, next nodes, checkpoint ancestry, namespaces, and thread identity. It supports behaviors such as fault recovery, history, replay, and fork. Pydantic AI message_history supplies model context; it does not provide those workflow guarantees.
Interrupt and approval semantics differ
LangGraph resume restarts the interrupted node from its beginning. Code before interrupt() runs again; multiple interrupts are matched by position. Keep pre-interrupt effects idempotent or move them after the interrupt/separate node.
When an interrupt merely asks for missing user input, preserve it as conversational workflow state: persist the pending question and phase, then append the answer as user protocol content on resume. Do not introduce an approval protocol unless a protected effect actually needs authorization.
For a protected-tool decision, Pydantic AI deferred approval ends or pauses at a tool-call boundary. An external resume supplies DeferredToolResults keyed by tool-call ID together with the original history. Pydantic AI does not automatically persist the history, dependencies, authenticated principal, or application resume token. Approval is not an authorization boundary: never trust a browser/client-provided DeferredToolResults merely because its ID is well formed. Authenticate the reviewer and correlate the result server-side to an issued pending call, authorized principal/tenant, tool name, and approved original arguments or an explicitly authorized override.
Map these details explicitly:
| LangChain/LangGraph behavior | Migration decision |
|---|---|
| ordered decisions for an interrupt batch | persist and map each decision to a stable Pydantic tool-call ID |
| approve, edit, reject, or respond | map approve/override/deny; design a result path for human respond behavior |
| node restarts on resume | decide which pre-interrupt hooks/effects must rerun or must not rerun |
| checkpointer owns thread resume | choose application/durable-workflow storage and atomic correlation |
| replay may re-execute later nodes | retain idempotency keys and reconcile unknown-after-crash outcomes |
Prove denial executes the protected tool zero times. Prove approval executes it exactly once with the original authenticated dependencies, correlation, and either the original arguments or a separately authorized override. Add crash injection before persistence, after persistence, before the side effect, and after an unknown side-effect outcome. Also forge an approval for another thread/tenant and an unknown or already-consumed tool-call ID; the server-side boundary must reject both before the agent or tool executes.
Middleware, retries, and limits
LangChain middleware order is behavioral: before hooks run in list order, after hooks in reverse, and wrappers nest with the first middleware outermost. Middleware can update graph state, jump, short-circuit, or transform model/tool calls. A flat list of Pydantic AI hooks does not prove the same nesting.
Trace exact order on success, validation failure, tool failure, interrupt, resume, cancellation, and terminal output. Decide whether behavior belongs in a hook, capability, toolset wrapper, model wrapper, output validator, tool body, or application boundary.
Keep retry domains separate:
| Source policy | Why it is not 1:1 | Likely owner |
|---|---|---|
LangGraph node RetryPolicy | reruns a node after selected exceptions/backoff | workflow or service retry |
| LangChain tool retry middleware | may turn tool errors into model-visible feedback | tool wrapper or ModelRetry only for model-correctable failures |
| provider/transport retry | repeats network requests without asking the model to change | model/provider transport |
| Pydantic AI output/tool retry | per-domain validation/model-correction budget | agent/tool/output configuration |
ModelRetry tells the model to try differently; do not use it as a generic transient-network retry. A repeated tool invocation may duplicate a side effect.
In particular, LangChain ToolRetryMiddleware can retry the same tool handler locally with the same request before returning to the model. Pydantic AI @agent.tool(retries=N) limits validation/ModelRetry feedback cycles that involve another model request. A direct translation can change model-call count, arguments, latency, and cost. Use a Hooks.on.tool_execute wrapper or service-client retry when the source guarantee is same-handler local retry; reserve ModelRetry for model-correctable failures. Spike a fail-once tool and count both model and tool calls.
Likewise, LangGraph recursion_limit, LangChain model-call middleware limits, Pydantic AI request_limit, and tool_calls_limit count different units and may fail differently. LangChain limit middleware can track a persisted thread total and may end with a synthetic assistant message; Pydantic AI run limits raise UsageLimitExceeded and reset unless the caller supplies accumulated usage. One verified Pydantic AI behavior is batch-atomic enforcement: if a parallel tool-call batch would exceed tool_calls_limit, none of that batch executes. Test boundary values, repeat across a persisted thread, and report the failure shape plus the unit each limit protects.
Streaming and event contracts
LangGraph stream modes can expose full state, state updates, model messages/tokens, custom events, checkpoints, tasks, and debug data. Pydantic AI exposes model-part, tool, deferred, node, and final-result events through different APIs. Neither event grammar is a public-contract replacement for the other.
Define a versioned application event envelope with correlation, sequence, event kind, payload, and terminal/error semantics. Then adapt both implementations to it during shadowing. In Pydantic AI event streams, emit the public terminal event from AgentRunResultEvent, which represents completed execution, rather than treating an earlier output-selection event as completion.
Probe:
ordering of token, tool-start, tool-result, approval, state-update, and final events;
whether final means model output chosen or all side effects completed;
cancellation and cleanup when the consumer disconnects;
reconnect/resume cursor behavior and duplicate delivery;
bounded buffering/backpressure for slow consumers;
event-loop responsiveness before the first model chunk: use a native async retrieval/tool path or offload blocking synchronous work, and probe that unrelated async work can still advance;
durable execution limitations, since some workflow integrations cannot stream in real time.
Concurrency and cancellation
LangGraph parallel nodes execute within super-steps and merge through channel reducers. Send creates dynamic branches. Pydantic AI function tools are concurrent by default when the model emits multiple calls; sequential=True makes a tool a barrier, and a run-level execution mode can serialize tools.
LangGraph rejects conflicting same-step writes when a channel has no suitable reducer; annotated reducers define combination. Pydantic Graph parallel tasks can share mutable state, so a mechanical state-port can turn a deterministic reducer or conflict into a race and lost update. Prefer branch-local results and an explicit typed join/reducer; do not use shared dependencies as a mutable state channel. Carry a source index when visible order matters, sort at the join, and use ReducerContext.cancel_sibling_tasks() when the reducer's contract ends remaining branch work.
Also test concurrent requests for the same persisted thread. An optimistic version check at final save can prevent a lost-state overwrite while both requests have already paid for model calls or executed tools. Preserve source serialization where promised, or claim/reserve the thread before dispatch and make effects idempotent. Report a final-save conflict as duplicate-work protection only when an executable probe proves that earlier work did not repeat.
Do not replace graph fan-out with default tool concurrency. Preserve:
maximum concurrency and rate limits;
deterministic result order versus completion order;
reducer/merge rules and duplicate keys;
sibling cancellation when one branch fails;
partial-result policy and retry scope;
event order separately from execution order;
side-effect isolation and compensation.
Spike a slow-first/fast-second pair. Prove overlap when allowed, barrier order when required, failure cancellation, and externally visible event ordering.
Spike protocol
Use TestModel for schema/registration checks and FunctionModel for exact trajectories. Disable live model requests. Keep each spike small enough to explain one semantic claim.
Pin and print LangChain, LangGraph, and Pydantic AI versions.
Build the smallest source reproduction and run it before translating.
Capture model-visible instructions, tool definitions, messages, events, state/checkpoints, calls, and side effects.
Build the smallest target reproduction using the proposed primitive.
Feed both the same fixture and compare an application-owned trace.
Add failure injection and boundary values, not only the success path.
Promote the probe to a parity test or record why it is version-specific and temporary.
At minimum, spike these when present:
two dynamic-instruction dependency values and a history continuation;
invalid and multiple structured outputs;
two source dynamic-prompt middleware entries versus composed Pydantic AI instructions;
output co-emitted with a successful and retrying tool under the chosen stream API;
a fail-once tool under LangChain retry middleware versus Pydantic AI retry feedback;
oversized parallel tool-call batch;
concurrent tools plus a sequential barrier;
interrupt/deny/approve with crash and replay injection;
same-step graph writes with and without a reducer;
malformed history containing dangling calls, orphan results, and duplicate message IDs;
a transitional
return_directtool and model-call count;per-run and persisted-thread limit exhaustion plus failure shape;
middleware order across failure and resume;
fan-out failure/cancellation and reducer order;
event sequence plus consumer cancellation.
Primary references
LangChain: middleware execution order, structured output, and human-in-the-loop
LangGraph: checkpointers, interrupts, fault tolerance, and streaming
Deep Agents: customization and default stack, human-in-the-loop, and fault tolerance
Pydantic AI: instructions, message history, structured output, parallel tools, deferred tools, and streaming
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