Running a sequence item in sequence and sequencer

How does starting, running and randomizing a sequence item on a sequencer differ from doing it on a sequence?
Till now, I have been using sequence class to run item eg.

//Sequencer
import uvm_pkg::*;
`include "pkg.sv"
`include "uvm_macros.svh"
import my_pkg::*;

class pkt_sequence extends uvm_sequence#(Packet);
		
	`uvm_object_utils(pkt_sequence)
	
	function new(string name = "Sequence of Packet");
		super.new(name);
	endfunction
	
	function void pre_randomize();
		`uvm_info("PRE", "Starting randomization of Packets", UVM_MEDIUM);
	endfunction
	
	function void post_randomize();
		`uvm_info("POST", "Finished randomization of Packets", UVM_MEDIUM);
	endfucntion
	
	task body();
		Packet pkt;
		pkt = Packet::type_id::create("Sequence of data", get_full_name());
		start_item(pkt);
		assert(pkt.randomize());
		finish_item(pkt);
	endtask
	
endclass

Now can I do the same thing from a sequencer instead? My sequencer is

//Sequencer
import uvm_pkg::*;
`include "uvm_macros.svh"

class pkt_sequencer extends uvm_sequencer#(Packet);

	`uvm_component_utils(pkt_sequencer);

	function new(string name="Sequencer", uvm_component parent);
		super.new(name, parent);
	endfunction

	function build_phase(uvm_phase phase);
		super.build_phase(phase);
	endfunction

endclass

In reply to smukerji:

The sequencer Needs a sequence. Because the sequence defines how the sequence items are generated.

In reply to chr_sue:

Certainly, but my question is Can I do my sequencer as

//Sequencer
import uvm_pkg::*;
`include “uvm_macros.svh”

class pkt_sequencer extends uvm_sequencer#(Packet);

`uvm_component_utils(pkt_sequencer);

function new(string name="Sequencer", uvm_component parent);
	super.new(name, parent);
endfunction

function build_phase(uvm_phase phase);
	super.build_phase(phase);
endfunction

    virtual task void run_phase(uvm_phase phase);
            **pkt_sequence.start(this);
            //OR
            `uvm_do(pkt_sequence);**
    endtask

endclass

In reply to smukerji:

No, you can’t do this. The run_phase Task is intended to perform the run Control and not the behavior of a sequence.
You should have a look to the Basics of UVM.

In reply to chr_sue:
Actually, you could do the pk_sequence.start(this), assuming you constructed the pkt_sequence beforehand. But it is not the recommend way.

A Sequence is a functor - an object that represents a handle to a routine - the sequence’s body() task in the UVM. You typically want your test to start the top-level sequence, and have it orchestrate the flow of all the other sequences in your tests. A sequence can start other other sequences in parallel or in series, and sequences can send transaction items (uvm_sequence_item) to the driver. The driver only sees sequence_items. The sequenceRs job is arbitrate the order of sequence items that get sent to the driver, and manage the protocol between the active sequence and driver. The sequencer typically has no user code associated with it.

In reply to dave_59:

Is there any motivation why should one prefer doing following:
start_item(pkt);
assert(pkt.randomize());
finish_item(pkt);

instead of:
assert(pkt.randomize());
start_item(pkt);
finish_item(pkt);

I see no critical disadvantage in following later. Kindly correct me if I am wrong.

In reply to usman_:

start_item() blocks until the driver executes get()and the sequencer picks the sequence that responds to that request. The advantage placing code in-between start_item()/finish_item() gives you the opportunity to perform any computation, including randomization, at the exact point in time the driver requests it. Then you can use the current state of the DUT or testbench to perform those computations. You may sometime see the term "*late-randomization*", but the principle apply to more than just randomization.