Dual-Agent Collaborative Development: An AI-Driven End-to-End Delivery Pipeline
The real bottleneck in AI-assisted development is not which coding assistant you pick, but the lack of adversarial review. This article describes a two-agent workflow that separates generation from review and splits one conversation into four roles: spec planner, implementer, auditor, and test designer. It walks through six phases — converging on a verifiable spec, constraining generation with a project-level convention file, implementing module by module with an audit right after each one, designing tests from acceptance criteria, adding human regression on UI and interaction, and running standard pre-release checks. It also gives objective criteria for freezing a spec, explains how to compensate for blind spots shared by agents built on the same model family, covers common failure modes such as formalized debate, over-engineering, spec-code drift, and treating audit comments as final conclusions, and shows how non-programmers can drive the same process.
1. The Problem Isn’t “Which Tool to Pick” — It’s the Missing Adversarial Pressure
The long-running argument about “which AI coding assistant do you prefer” points in the wrong direction. Tool preference was never the real bottleneck. The bottleneck is three structural weaknesses of single-pass, conversational generation:
- Context decay. As a conversation grows longer, constraints established early (field naming, error code conventions, API versions) get diluted by everything that follows. The model starts losing track of the boundaries and produces code that is inconsistent with the existing design.
- Self-confirmation bias. When the same model is both author and reviewer, it tends to defend what it already wrote rather than hunt for holes. Its “review comments” often turn out to be a restatement of its own output.
- Requirement hallucination. When a requirement is described vaguely, the model fills in business rules it does not actually know and writes those guesses as if they were established fact. The defect is not incorrect code — it is a feature nobody asked for.
Splitting generation and review across two independent agents is precisely a way to inject an external adversarial signal, so that errors surface during the document stage and the module stage instead of collapsing at integration time. The workflow below is built around that single goal.
2. Role Split: Four Responsibilities Instead of One Conversation
Rather than letting one agent own the whole pipeline, separate by responsibility. Each role cares about exactly one thing:
| Role | Responsibility | Deliverables |
|---|---|---|
| Spec planner | Clarify requirements, define boundaries, break down modules | Spec document, module list, acceptance criteria |
| Implementer | Write code against the finalized spec | Code, configuration, necessary explanatory comments |
| Auditor | Check deviation from spec, security, maintainability | Tiered issue list (blocking / recommended / questionable) |
| Test designer | Derive executable cases from the spec | Test case matrix, test data, assertion points |
The critical point is the separation of read-only and write-only: the planning and audit phases produce text opinions only and commit no code changes; only the implementation phase is allowed to write files. This discipline prevents two agents from editing code at each other during a discussion and ending up with a version nobody can account for.
3. Phase 1: Requirements Convergence and an Acceptable Spec
This is the highest-return step in the entire pipeline. How clear the spec is directly determines the cost of every subsequent round of rework.
Have the planner output an “open questions list” first, not a solution. An effective prompt looks like this:
Do not write code or propose an implementation yet.Based on the requirements below, list:1) The parts you consider already clear (restate each one so I can confirm)2) The parts that are ambiguous and require my decision (give 2–3 candidate options per item, along with the cost of each)3) The assumptions you are making that have not been verified (mark them as "assumptions to be verified")4) The feature points for which acceptance criteria cannot be determined with the current informationRequirements: <paste the business description>
Items 2 and 3 are the ones that matter. Surfacing the vague parts explicitly is far safer than letting the model quietly decide them on your behalf.
Then bring in a second agent to push back. Hand the draft spec to the auditor role and explicitly require it to speak from the position of “under what conditions does this spec break?” For example: missing boundary conditions, undefined error paths, performance assumptions that no longer hold as data volume grows, a permission model that fails to cover some role.
Convergence needs an objective stopping condition, not a feeling that it is “close enough.” Use countable criteria:
- The open questions list has not grown for two consecutive rounds;
- Every acceptance criterion maps to at least one observable input/output pair;
- Every “assumption to be verified” has been marked as either confirmed or eliminated;
- The module split satisfies “each module can be accepted independently,” meaning every module has its own success criterion.
If any one of these fails, keep debating. Only when all of them hold do you freeze the spec. Freezing means that any requirement added afterward must go through a change process (written into the document, impact re-evaluated) rather than being appended casually in conversation.
4. Phase 2: Constraining Generation Behavior with a Project-Level Convention File
The spec answers “what to build.” The convention file answers “how to build it.” It is a long-lived text constraint kept in the project root, read at the start of every session, and its job is to eliminate repeated explanations and style drift.
A practical skeleton:
# Project Conventions## Technical Boundaries- Tech stack is fixed at: <language / framework version>- Do not introduce new third-party dependencies unless the reason is documented and confirmed- All external access must go through a unified data access layer## Code Standards- Naming: <convention>- No function longer than N lines; when exceeded, it must be split and the rationale stated- No mutable global state- All exported functions must have doc comments describing parameters, return values, and thrown conditions## Working Discipline- Do not modify <protected directories> without explicit permission- Do not delete existing tests; if a change is required, explain the reason first- After each module is complete, output a change summary: new files, modified files, impact scope## Definition of Done- Passes static checks and formatting- Unit tests cover all branches of the module- No new warning logs
The value of the convention file is that it accumulates: every manual correction (“don’t concatenate SQL inline here,” “API responses always use the wrapper structure”) should be written back into it. It converts one-off reminders into long-term constraints, and as the project progresses the model’s error rate drops noticeably.
5. Phases 3 and 4: Module-by-Module Implementation and Cross-Audit
Advance by module, not by file. The dividing principle for a module is a “vertically sliced unit that can be accepted independently”: a module should contain its data, logic, interface, and its own means of verification, and be runnable on its own. That way each module’s output can be reviewed in isolation, and defects do not spread across module boundaries.
Implementation instructions should be extremely specific. Avoid open-ended phrasing like “help me implement this feature”:
Implement only <module name> as described in section 3.2 of the spec document.Follow every clause of the project convention file.When finished, output: list of changed files, key design decisions with their rationale, and any parts you did not implement or are unsure about.Do not refactor unrelated code along the way.
The last line matters especially. “Improving things in passing” is a common source of uncontrolled changes in AI output and must be prohibited explicitly.
Audit immediately after each module; do not batch it to the end. Audit findings need severity levels, otherwise a list where everything is “recommend optimization” has no action value:
- Blocking: inconsistent with the spec, carries security or data risk, or will crash at runtime;
- Important: missing boundary conditions, unhandled exceptions, performance assumptions that do not hold;
- Optional: naming, readability, structural improvements.
Then have the implementer respond to each item: accept, rebut, or flag as needing human decision. A rebuttal must come with a reason and evidence, not a restatement of the original implementation. Key discipline: only blocking and important items require consensus; optional items are always resolved with the minimal change, and large-scale refactoring is forbidden. This single rule blocks most cases where a “debate” turns into a rewrite.
One easily overlooked checkpoint: when two agents share the same origin, they share the same blind spots. If both sides are driven by the same model family, they tend to have identical blind spots on common error classes (certain concurrency scenarios, timezone handling, floating-point comparison), and mutual auditing yields limited benefit. There are two mitigations: first, have the auditor explicitly work through a fixed high-risk checklist (concurrency, transaction boundaries, timezones and character encoding, numeric precision, null values, idempotency, permission checks, excessively long input); second, bring in deterministic tools such as static analysis and type checking to mechanically cover part of what the models miss.
6. Phases 5 and 6: Test Design and Human Fill-In
The test plan should also be designed before it is executed. Have the test designer derive cases from the acceptance criteria in the spec, not from the implementation code. The former “verifies the requirement”; the latter easily becomes “verifies the current state of the code,” freezing incorrect behavior into assertions.
Organize cases by dimension in a table to avoid gaps:
| Dimension | Example focus points |
|---|---|
| Happy path | Inputs and outputs of each branch of the main flow |
| Boundary values | 0, 1, maximum length, empty collection, very large files |
| Exceptions | Dependency unavailable, timeout, duplicate submission, partial failure |
| Permissions | No permission, privilege escalation, expired credentials |
| Data | Dirty data, backward compatibility, character sets |
| Performance | Response time and resource usage under large data volumes |
One reality check is needed: AI is good at generating large numbers of well-branched unit-level cases and poor at catching interaction- and presentation-level problems. Broken layout, inconsistent spacing, missing state feedback, flickering loading states, unfriendly error messages, awkward keyboard and accessibility behavior — these are almost impossible to catch with code assertions. So human regression is not an optional step but a formal part of the pipeline, and it should concentrate on the UI and interaction layer, backed by end-to-end scripts covering the critical paths.
7. Deployment and Observability: Bringing AI Output Under Normal Engineering Governance
AI-generated code is subject to the same operational constraints as human-written code. “The AI wrote it” is not a reason to skip pre-release checks.
When you host this kind of application on Baidu AI Cloud, you can close the loop with a commonly used combination of cloud capabilities: a container platform for running the service and elastic scaling, object storage for static assets and build artifacts, a message queue for asynchronous decoupling, a log service for centralized log collection, and monitoring and alerting for metric observation and exception notification. These are general cloud product categories; refer to the official documentation for specific configuration.
Minimum pre-release checklist:
- Have keys and credentials been moved into configuration or a secret management mechanism, with no plaintext left in code or the repository?
- Does every externally exposed interface have a permission check, and is there any write operation reachable without authentication?
- Do logs contain sensitive information, and are sampling and retention periods set sensibly?
- Are critical paths instrumented, and are alert thresholds justified?
- Has the rollback path actually been verified, rather than being “theoretically fine”?
8. Common Pitfalls and How to Avoid Them
- Debate becomes a formality. The two agents repeatedly tell each other “you’re right” with the same phrasing; rounds increase but information does not. Fix: require each round to output structured “new findings,” and declare convergence after one round with none.
- Over-engineering. Multi-round discussion naturally pushes solutions toward greater complexity. Fix: write non-goals (Out of Scope) explicitly during the spec phase, and add “prefer the simpler implementation unless the added complexity brings a measurable benefit” to the convention file.
- Documentation drifts from code. The spec keeps evolving after sign-off while the document stays on an old version, so later sessions work from stale information. Fix: make document updates part of the definition of done, and land spec changes in the same batch.
- Treating audit findings as conclusions. The auditor is also wrong sometimes, especially on subjective judgments about performance and concurrency. Fix: separate “factual defects” from “style preferences.” The former require verification (reproduction or a proving test case); the latter are settled by the convention file.
- Skipping the nodes that require human decisions. Pricing, compliance, user-visible behavior, and data retention policy cannot be delegated to an agent. Fix: list a “human decision items” section in the spec document, and do not enter implementation until those are confirmed.
9. Practical Advice for Non-Programmers
You can drive this workflow without writing code. Four things are what matter:
- Write requirements as observable behavior: “after the user clicks submit, a success message appears within 2 seconds; on failure the specific reason is shown and already-entered content is not lost,” rather than “the experience should be good.”
- Demand a traceable decision record: in every round, have the agent output “what was decided, on what basis, and which alternatives were rejected.” That record is your only thread when you need to investigate a problem later.
- Insist on small-step delivery: advance one module at a time, and only move on after acceptance. Accepting large batches of unverified code in bulk just piles risk up to a point where nothing can be localized.
- Keep the human veto: any feature whose reason for existing you cannot explain should be deleted or justified.
Conclusion: The difference made by tool choice is far smaller than the difference made by process design. Chain requirements convergence, generation constraints, module breakdown, cross-audit, test design, and human regression into a fixed rhythm, and any assistant with planning and coding ability can produce usable results. Without that rhythm, even the strongest model can only deliver code that looks reasonable and cannot actually ship.
